emby-cli 0.3.0__tar.gz → 0.4.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.
- {emby_cli-0.3.0 → emby_cli-0.4.1}/CHANGELOG.md +11 -0
- emby_cli-0.4.1/PKG-INFO +242 -0
- emby_cli-0.4.1/README.md +208 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/_version.py +2 -2
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/cli.py +63 -10
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/client.py +9 -5
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/download.py +20 -15
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/help.py +1 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/search.py +17 -11
- emby_cli-0.4.1/src/emby_cli/commands/show.py +273 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/constants.py +11 -0
- emby_cli-0.4.1/src/emby_cli/mode_args.py +31 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_client.py +13 -7
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_parser.py +79 -17
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_search.py +7 -7
- emby_cli-0.4.1/tests/test_show.py +142 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_validate_args.py +58 -19
- emby_cli-0.3.0/PKG-INFO +0 -129
- emby_cli-0.3.0/README.md +0 -95
- {emby_cli-0.3.0 → emby_cli-0.4.1}/.env.example +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/.github/workflows/ci.yml +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/.github/workflows/publish.yml +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/.gitignore +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/LICENSE +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/pyproject.toml +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/__init__.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/__main__.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/auth_cache.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/__init__.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/config.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/info.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/login.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/logout.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/play.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/commands/version.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/credentials.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/download_ops.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/output.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/resolve.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/util.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/src/emby_cli/version.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_auth_cache.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_config.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_credentials.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_download_ops.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_info.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_logout.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_output.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_resolve.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_resolve_table.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_session_auth.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_util.py +0 -0
- {emby_cli-0.3.0 → emby_cli-0.4.1}/tests/test_version.py +0 -0
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.4.1
|
|
6
|
+
|
|
7
|
+
- README rewritten for end users (quick start, everyday workflows, responsible-use disclaimer).
|
|
8
|
+
|
|
9
|
+
## 0.4.0
|
|
10
|
+
|
|
11
|
+
Added:
|
|
12
|
+
|
|
13
|
+
- `show`: detail view for `--item` / `--library` (QUERY or `--id`); multiple matches print a disambiguation table with IDs. Libraries include total item count and the last 10 added (`DateCreated`), limited to Movie/Episode/Audio (no Studio, etc.).
|
|
14
|
+
- `search` / `download`: `--item QUERY` / `--library QUERY` (query on the mode flag); `--media-item` is an alias of `--item`. `--search` still works as an alternative selector.
|
|
15
|
+
|
|
5
16
|
## 0.3.0
|
|
6
17
|
|
|
7
18
|
Breaking:
|
emby_cli-0.4.1/PKG-INFO
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: emby-cli
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: CLI to list, search, play, and download/backup original media from an Emby server via its REST API.
|
|
5
|
+
Project-URL: Homepage, https://github.com/soukron/emby-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/soukron/emby-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/soukron/emby-cli/issues
|
|
8
|
+
Author-email: Sergio Garcia <soukron@gmbros.net>
|
|
9
|
+
Maintainer-email: Sergio Garcia <soukron@gmbros.net>
|
|
10
|
+
License-Expression: CC-BY-NC-4.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: backup,cli,download,emby,media
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: License :: Free for non-commercial use
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Multimedia :: Video
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Requires-Dist: m3u8>=4.0
|
|
26
|
+
Requires-Dist: requests>=2.31
|
|
27
|
+
Requires-Dist: static-ffmpeg>=3.0
|
|
28
|
+
Requires-Dist: tqdm>=4.66
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# emby-cli
|
|
36
|
+
|
|
37
|
+
[PyPI](https://pypi.org/project/emby-cli/)
|
|
38
|
+
· [License: CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
39
|
+
|
|
40
|
+
Search, browse, play, and download media from your [Emby](https://emby.media/) server — from the terminal. Only HTTP access to the server is needed (typically port 8096). No SSH, no shared folders, no rsync.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install emby-cli
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
**1. Log in once** (username + password, or an API key):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
emby-cli login --server http://emby:8096 --username you
|
|
54
|
+
# prompted for password if not set
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Your session is saved locally. Later commands reuse it, so you usually do not need to pass `--server` again.
|
|
58
|
+
|
|
59
|
+
**2. Check the connection:**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
emby-cli info
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**3. Search and download:**
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
emby-cli search --item "matrix"
|
|
69
|
+
emby-cli download --item "matrix" --pick-best-item
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use `emby-cli help` for the command list, and `emby-cli <command> -h` for options.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Everyday use
|
|
77
|
+
|
|
78
|
+
### Server info
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
emby-cli version # CLI version (and Emby version when connected)
|
|
82
|
+
emby-cli info # user, server, library count, content totals
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Search
|
|
86
|
+
|
|
87
|
+
Find movies, episodes, and other media — or list libraries:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
emby-cli search --item "fast and furious"
|
|
91
|
+
emby-cli search --item "fast and furious" --count 50
|
|
92
|
+
emby-cli search --item --id 123456
|
|
93
|
+
emby-cli search --library "peliculas"
|
|
94
|
+
emby-cli search --library --all
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`--item` and `--library` accept the search text directly. You can also pass `--id` when you already know the Emby ID.
|
|
98
|
+
|
|
99
|
+
### Show details
|
|
100
|
+
|
|
101
|
+
Inspect one title or one library (counts, metadata, recently added):
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
emby-cli show --item "matrix"
|
|
105
|
+
emby-cli show --item --id 123456
|
|
106
|
+
emby-cli show --library "peliculas"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If several titles match, `show` lists them with IDs so you can pick one:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
emby-cli show --item --id 123456
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Play
|
|
116
|
+
|
|
117
|
+
Open a title in an external player (VLC, mpv, IINA, …):
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
emby-cli play --search "Pelicula (1980)" --pick-best-item
|
|
121
|
+
emby-cli play --id 123456
|
|
122
|
+
emby-cli play --id 123456 --player vlc --wait
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Set `EMBY_PLAYER` if the player is not found automatically.
|
|
126
|
+
|
|
127
|
+
### Download
|
|
128
|
+
|
|
129
|
+
Download a single title, a whole library, or a list of titles from a file:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
emby-cli download --item --id 123456
|
|
133
|
+
emby-cli download --item "californication S01E01" --pick-best-item
|
|
134
|
+
emby-cli download --library "PELICULAS 4K"
|
|
135
|
+
emby-cli download --from-file titles.txt
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Useful options:
|
|
139
|
+
|
|
140
|
+
| Option | Meaning |
|
|
141
|
+
|--------|---------|
|
|
142
|
+
| `-n` / `--dry-run` | Resolve titles only — do not write files |
|
|
143
|
+
| `-o` / `--output` | Output folder (default `./downloads`) |
|
|
144
|
+
| `-f` / `--force` | Re-download even if a matching local file exists |
|
|
145
|
+
| `--pick-best-item` | When several versions match, pick the best ≤1080p |
|
|
146
|
+
| `-m download\|stream\|hls` | How to fetch the file (see below) |
|
|
147
|
+
|
|
148
|
+
**Title lines** in `--item` / `--from-file` can look like:
|
|
149
|
+
|
|
150
|
+
- `Movie (2010)`
|
|
151
|
+
- `Show S01E05`
|
|
152
|
+
- `Show S01` — whole season (with `--item` or `--from-file`)
|
|
153
|
+
|
|
154
|
+
By default, matching is **strict**: a wrong year or several ambiguous results stops with a table of candidates. Add `--pick-best-item` to choose automatically (best quality up to 1080p).
|
|
155
|
+
|
|
156
|
+
Library downloads match the library **name** (case-insensitive, unique match required).
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Logging in and switching servers
|
|
161
|
+
|
|
162
|
+
| Approach | When to use |
|
|
163
|
+
|----------|-------------|
|
|
164
|
+
| `emby-cli login` | Recommended — saves a session and remembers the server |
|
|
165
|
+
| API key | `--api-key` / `EMBY_API_KEY` (keys are not stored by `login`) |
|
|
166
|
+
| Flags / env | `--server`, `--username`, `--password` or `EMBY_*` for one-off use |
|
|
167
|
+
|
|
168
|
+
Manage saved servers:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
emby-cli config get-servers
|
|
172
|
+
emby-cli config current-server
|
|
173
|
+
emby-cli config use-server 'you@http://emby:8096'
|
|
174
|
+
emby-cli config view # tokens redacted
|
|
175
|
+
emby-cli logout # revoke and forget the current session
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Sessions live under `~/.cache/emby-cli/auth.json` (override with `EMBY_CACHE_DIR`). Set `EMBY_NO_AUTH_CACHE=1` to never read or write the cache.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Download methods
|
|
183
|
+
|
|
184
|
+
Choose with `-m` / `EMBY_METHOD`:
|
|
185
|
+
|
|
186
|
+
| Method | Best for |
|
|
187
|
+
|--------|----------|
|
|
188
|
+
| `download` (default) | Normal file download from Emby |
|
|
189
|
+
| `stream` | Direct stream URL (similar to Emby Web) |
|
|
190
|
+
| `hls` | HLS remux to `.mkv` |
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Configuration reference
|
|
195
|
+
|
|
196
|
+
Flags override environment variables. Optional template: `.env.example` (export the vars yourself — the CLI does not load `.env` files).
|
|
197
|
+
|
|
198
|
+
| Variable | Description |
|
|
199
|
+
|----------|-------------|
|
|
200
|
+
| `EMBY_SERVER` | Server URL |
|
|
201
|
+
| `EMBY_API_KEY` | API key |
|
|
202
|
+
| `EMBY_USERNAME` / `EMBY_PASSWORD` | Username / password |
|
|
203
|
+
| `EMBY_OUTPUT` | Download directory (default `./downloads`) |
|
|
204
|
+
| `EMBY_METHOD` | `download`, `stream`, or `hls` |
|
|
205
|
+
| `EMBY_PLAYER` | External player command or path |
|
|
206
|
+
| `EMBY_ITEM_ID` | Default `--id` for item download / play |
|
|
207
|
+
| `EMBY_CACHE_DIR` | Credentials directory (default `~/.cache/emby-cli`) |
|
|
208
|
+
| `EMBY_NO_AUTH_CACHE` | `1` = disable session cache |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Tips
|
|
213
|
+
|
|
214
|
+
- Prefer **search → show → download** when you are unsure of the exact title.
|
|
215
|
+
- Prefer **IDs** (`--id`) when you already have them — no ambiguity.
|
|
216
|
+
- Use **`--dry-run`** before a large library or file-list download.
|
|
217
|
+
- Content totals in `info` can count multiple versions of the same title separately.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Responsible use
|
|
222
|
+
|
|
223
|
+
This tool talks to Emby over its normal HTTP API. Whether download or playback is allowed depends on **how that server is configured** and on **the terms set by whoever runs it**.
|
|
224
|
+
|
|
225
|
+
Use `emby-cli` only on servers you are authorized to access, and only in ways that comply with that server’s terms of use, policies, and applicable law. The authors provide the software as-is and are **not responsible** for misuse, for downloads from servers that disallow them, or for any consequences of using the tool.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## For contributors
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
233
|
+
pip install -e ".[dev]"
|
|
234
|
+
pytest -q
|
|
235
|
+
python -m build && twine check dist/*
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Releases: tag `vX.Y.Z` and push (or create a GitHub Release). CI publishes to PyPI via Trusted Publisher.
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
[CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) — free for non-commercial use.
|
emby_cli-0.4.1/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# emby-cli
|
|
2
|
+
|
|
3
|
+
[PyPI](https://pypi.org/project/emby-cli/)
|
|
4
|
+
· [License: CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
5
|
+
|
|
6
|
+
Search, browse, play, and download media from your [Emby](https://emby.media/) server — from the terminal. Only HTTP access to the server is needed (typically port 8096). No SSH, no shared folders, no rsync.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install emby-cli
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
**1. Log in once** (username + password, or an API key):
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
emby-cli login --server http://emby:8096 --username you
|
|
20
|
+
# prompted for password if not set
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Your session is saved locally. Later commands reuse it, so you usually do not need to pass `--server` again.
|
|
24
|
+
|
|
25
|
+
**2. Check the connection:**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
emby-cli info
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**3. Search and download:**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
emby-cli search --item "matrix"
|
|
35
|
+
emby-cli download --item "matrix" --pick-best-item
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Use `emby-cli help` for the command list, and `emby-cli <command> -h` for options.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Everyday use
|
|
43
|
+
|
|
44
|
+
### Server info
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
emby-cli version # CLI version (and Emby version when connected)
|
|
48
|
+
emby-cli info # user, server, library count, content totals
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Search
|
|
52
|
+
|
|
53
|
+
Find movies, episodes, and other media — or list libraries:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
emby-cli search --item "fast and furious"
|
|
57
|
+
emby-cli search --item "fast and furious" --count 50
|
|
58
|
+
emby-cli search --item --id 123456
|
|
59
|
+
emby-cli search --library "peliculas"
|
|
60
|
+
emby-cli search --library --all
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`--item` and `--library` accept the search text directly. You can also pass `--id` when you already know the Emby ID.
|
|
64
|
+
|
|
65
|
+
### Show details
|
|
66
|
+
|
|
67
|
+
Inspect one title or one library (counts, metadata, recently added):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
emby-cli show --item "matrix"
|
|
71
|
+
emby-cli show --item --id 123456
|
|
72
|
+
emby-cli show --library "peliculas"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If several titles match, `show` lists them with IDs so you can pick one:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
emby-cli show --item --id 123456
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Play
|
|
82
|
+
|
|
83
|
+
Open a title in an external player (VLC, mpv, IINA, …):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
emby-cli play --search "Pelicula (1980)" --pick-best-item
|
|
87
|
+
emby-cli play --id 123456
|
|
88
|
+
emby-cli play --id 123456 --player vlc --wait
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Set `EMBY_PLAYER` if the player is not found automatically.
|
|
92
|
+
|
|
93
|
+
### Download
|
|
94
|
+
|
|
95
|
+
Download a single title, a whole library, or a list of titles from a file:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
emby-cli download --item --id 123456
|
|
99
|
+
emby-cli download --item "californication S01E01" --pick-best-item
|
|
100
|
+
emby-cli download --library "PELICULAS 4K"
|
|
101
|
+
emby-cli download --from-file titles.txt
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Useful options:
|
|
105
|
+
|
|
106
|
+
| Option | Meaning |
|
|
107
|
+
|--------|---------|
|
|
108
|
+
| `-n` / `--dry-run` | Resolve titles only — do not write files |
|
|
109
|
+
| `-o` / `--output` | Output folder (default `./downloads`) |
|
|
110
|
+
| `-f` / `--force` | Re-download even if a matching local file exists |
|
|
111
|
+
| `--pick-best-item` | When several versions match, pick the best ≤1080p |
|
|
112
|
+
| `-m download\|stream\|hls` | How to fetch the file (see below) |
|
|
113
|
+
|
|
114
|
+
**Title lines** in `--item` / `--from-file` can look like:
|
|
115
|
+
|
|
116
|
+
- `Movie (2010)`
|
|
117
|
+
- `Show S01E05`
|
|
118
|
+
- `Show S01` — whole season (with `--item` or `--from-file`)
|
|
119
|
+
|
|
120
|
+
By default, matching is **strict**: a wrong year or several ambiguous results stops with a table of candidates. Add `--pick-best-item` to choose automatically (best quality up to 1080p).
|
|
121
|
+
|
|
122
|
+
Library downloads match the library **name** (case-insensitive, unique match required).
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Logging in and switching servers
|
|
127
|
+
|
|
128
|
+
| Approach | When to use |
|
|
129
|
+
|----------|-------------|
|
|
130
|
+
| `emby-cli login` | Recommended — saves a session and remembers the server |
|
|
131
|
+
| API key | `--api-key` / `EMBY_API_KEY` (keys are not stored by `login`) |
|
|
132
|
+
| Flags / env | `--server`, `--username`, `--password` or `EMBY_*` for one-off use |
|
|
133
|
+
|
|
134
|
+
Manage saved servers:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
emby-cli config get-servers
|
|
138
|
+
emby-cli config current-server
|
|
139
|
+
emby-cli config use-server 'you@http://emby:8096'
|
|
140
|
+
emby-cli config view # tokens redacted
|
|
141
|
+
emby-cli logout # revoke and forget the current session
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Sessions live under `~/.cache/emby-cli/auth.json` (override with `EMBY_CACHE_DIR`). Set `EMBY_NO_AUTH_CACHE=1` to never read or write the cache.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Download methods
|
|
149
|
+
|
|
150
|
+
Choose with `-m` / `EMBY_METHOD`:
|
|
151
|
+
|
|
152
|
+
| Method | Best for |
|
|
153
|
+
|--------|----------|
|
|
154
|
+
| `download` (default) | Normal file download from Emby |
|
|
155
|
+
| `stream` | Direct stream URL (similar to Emby Web) |
|
|
156
|
+
| `hls` | HLS remux to `.mkv` |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Configuration reference
|
|
161
|
+
|
|
162
|
+
Flags override environment variables. Optional template: `.env.example` (export the vars yourself — the CLI does not load `.env` files).
|
|
163
|
+
|
|
164
|
+
| Variable | Description |
|
|
165
|
+
|----------|-------------|
|
|
166
|
+
| `EMBY_SERVER` | Server URL |
|
|
167
|
+
| `EMBY_API_KEY` | API key |
|
|
168
|
+
| `EMBY_USERNAME` / `EMBY_PASSWORD` | Username / password |
|
|
169
|
+
| `EMBY_OUTPUT` | Download directory (default `./downloads`) |
|
|
170
|
+
| `EMBY_METHOD` | `download`, `stream`, or `hls` |
|
|
171
|
+
| `EMBY_PLAYER` | External player command or path |
|
|
172
|
+
| `EMBY_ITEM_ID` | Default `--id` for item download / play |
|
|
173
|
+
| `EMBY_CACHE_DIR` | Credentials directory (default `~/.cache/emby-cli`) |
|
|
174
|
+
| `EMBY_NO_AUTH_CACHE` | `1` = disable session cache |
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Tips
|
|
179
|
+
|
|
180
|
+
- Prefer **search → show → download** when you are unsure of the exact title.
|
|
181
|
+
- Prefer **IDs** (`--id`) when you already have them — no ambiguity.
|
|
182
|
+
- Use **`--dry-run`** before a large library or file-list download.
|
|
183
|
+
- Content totals in `info` can count multiple versions of the same title separately.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Responsible use
|
|
188
|
+
|
|
189
|
+
This tool talks to Emby over its normal HTTP API. Whether download or playback is allowed depends on **how that server is configured** and on **the terms set by whoever runs it**.
|
|
190
|
+
|
|
191
|
+
Use `emby-cli` only on servers you are authorized to access, and only in ways that comply with that server’s terms of use, policies, and applicable law. The authors provide the software as-is and are **not responsible** for misuse, for downloads from servers that disallow them, or for any consequences of using the tool.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## For contributors
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
199
|
+
pip install -e ".[dev]"
|
|
200
|
+
pytest -q
|
|
201
|
+
python -m build && twine check dist/*
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Releases: tag `vX.Y.Z` and push (or create a GitHub Release). CI publishes to PyPI via Trusted Publisher.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
[CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) — free for non-commercial use.
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.4.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 4, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -21,6 +21,7 @@ from emby_cli.commands.login import cmd_login
|
|
|
21
21
|
from emby_cli.commands.logout import cmd_logout
|
|
22
22
|
from emby_cli.commands.play import cmd_play, validate_play_args
|
|
23
23
|
from emby_cli.commands.search import cmd_search, validate_search_args
|
|
24
|
+
from emby_cli.commands.show import cmd_show, validate_show_args
|
|
24
25
|
from emby_cli.commands.version import cmd_version
|
|
25
26
|
from emby_cli.constants import DEFAULT_OUTPUT, SEARCH_COUNT_DEFAULT
|
|
26
27
|
from emby_cli.credentials import (
|
|
@@ -82,14 +83,23 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
82
83
|
)
|
|
83
84
|
mode = dl.add_mutually_exclusive_group(required=True)
|
|
84
85
|
mode.add_argument(
|
|
86
|
+
"--item",
|
|
85
87
|
"--media-item",
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
nargs="?",
|
|
89
|
+
const="",
|
|
90
|
+
default=None,
|
|
91
|
+
metavar="QUERY",
|
|
92
|
+
dest="item",
|
|
93
|
+
help="Download media items; optional QUERY, or use with --id "
|
|
94
|
+
"(--media-item is an alias)",
|
|
88
95
|
)
|
|
89
96
|
mode.add_argument(
|
|
90
97
|
"--library",
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
nargs="?",
|
|
99
|
+
const="",
|
|
100
|
+
default=None,
|
|
101
|
+
metavar="QUERY",
|
|
102
|
+
help="Download a library; optional QUERY, or use with --id",
|
|
93
103
|
)
|
|
94
104
|
mode.add_argument(
|
|
95
105
|
"--from-file",
|
|
@@ -105,7 +115,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
105
115
|
)
|
|
106
116
|
dl.add_argument(
|
|
107
117
|
"--search",
|
|
108
|
-
help="Search query
|
|
118
|
+
help="Search query (alternative to QUERY on --item / --library)",
|
|
109
119
|
)
|
|
110
120
|
dl.add_argument(
|
|
111
121
|
"--dry-run",
|
|
@@ -146,14 +156,23 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
146
156
|
sr = sub.add_parser("search", help=_help_by_name["search"])
|
|
147
157
|
sr_mode = sr.add_mutually_exclusive_group(required=True)
|
|
148
158
|
sr_mode.add_argument(
|
|
159
|
+
"--item",
|
|
149
160
|
"--media-item",
|
|
150
|
-
|
|
151
|
-
|
|
161
|
+
nargs="?",
|
|
162
|
+
const="",
|
|
163
|
+
default=None,
|
|
164
|
+
metavar="QUERY",
|
|
165
|
+
dest="item",
|
|
166
|
+
help="Search media items; optional QUERY, or use with --id / --all "
|
|
167
|
+
"(--media-item is an alias)",
|
|
152
168
|
)
|
|
153
169
|
sr_mode.add_argument(
|
|
154
170
|
"--library",
|
|
155
|
-
|
|
156
|
-
|
|
171
|
+
nargs="?",
|
|
172
|
+
const="",
|
|
173
|
+
default=None,
|
|
174
|
+
metavar="QUERY",
|
|
175
|
+
help="Search libraries; optional QUERY, or use with --id / --all",
|
|
157
176
|
)
|
|
158
177
|
sr.add_argument(
|
|
159
178
|
"--id",
|
|
@@ -162,7 +181,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
162
181
|
)
|
|
163
182
|
sr.add_argument(
|
|
164
183
|
"--search",
|
|
165
|
-
help="Search query
|
|
184
|
+
help="Search query (alternative to QUERY on --item / --library)",
|
|
166
185
|
)
|
|
167
186
|
sr.add_argument(
|
|
168
187
|
"--all",
|
|
@@ -206,6 +225,37 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
206
225
|
"(default: list matches and fail)",
|
|
207
226
|
)
|
|
208
227
|
|
|
228
|
+
sh = sub.add_parser("show", help=_help_by_name["show"])
|
|
229
|
+
sh_mode = sh.add_mutually_exclusive_group(required=True)
|
|
230
|
+
sh_mode.add_argument(
|
|
231
|
+
"--item",
|
|
232
|
+
"--media-item",
|
|
233
|
+
nargs="?",
|
|
234
|
+
const="",
|
|
235
|
+
default=None,
|
|
236
|
+
metavar="QUERY",
|
|
237
|
+
dest="item",
|
|
238
|
+
help="Show a media item; optional QUERY, or use with --id "
|
|
239
|
+
"(--media-item is an alias)",
|
|
240
|
+
)
|
|
241
|
+
sh_mode.add_argument(
|
|
242
|
+
"--library",
|
|
243
|
+
nargs="?",
|
|
244
|
+
const="",
|
|
245
|
+
default=None,
|
|
246
|
+
metavar="QUERY",
|
|
247
|
+
help="Show a library; optional QUERY, or use with --id",
|
|
248
|
+
)
|
|
249
|
+
sh.add_argument(
|
|
250
|
+
"--id",
|
|
251
|
+
default=None,
|
|
252
|
+
help="Media item or library ID",
|
|
253
|
+
)
|
|
254
|
+
sh.add_argument(
|
|
255
|
+
"--search",
|
|
256
|
+
help="Search query (alternative to QUERY on --item / --library)",
|
|
257
|
+
)
|
|
258
|
+
|
|
209
259
|
sub.add_parser("version", help=_help_by_name["version"])
|
|
210
260
|
sub.add_parser("info", help=_help_by_name["info"])
|
|
211
261
|
|
|
@@ -249,6 +299,8 @@ def _validate_command_args(command: str, args: argparse.Namespace) -> str | None
|
|
|
249
299
|
return validate_download_args(args)
|
|
250
300
|
if command == "play":
|
|
251
301
|
return validate_play_args(args)
|
|
302
|
+
if command == "show":
|
|
303
|
+
return validate_show_args(args)
|
|
252
304
|
return None
|
|
253
305
|
|
|
254
306
|
|
|
@@ -293,6 +345,7 @@ def main() -> None:
|
|
|
293
345
|
"download": cmd_download,
|
|
294
346
|
"search": cmd_search,
|
|
295
347
|
"play": cmd_play,
|
|
348
|
+
"show": cmd_show,
|
|
296
349
|
}
|
|
297
350
|
commands[args.command](client, args)
|
|
298
351
|
|
|
@@ -458,15 +458,19 @@ class EmbyClient:
|
|
|
458
458
|
recursive: bool = True,
|
|
459
459
|
start: int = 0,
|
|
460
460
|
limit: int = 200,
|
|
461
|
+
*,
|
|
462
|
+
sort_by: str = "SortName",
|
|
463
|
+
sort_order: str = "Ascending",
|
|
464
|
+
fields: str | None = None,
|
|
461
465
|
) -> dict:
|
|
462
466
|
uid = self.resolve_user_id()
|
|
463
467
|
params: dict = {
|
|
464
468
|
"StartIndex": start,
|
|
465
469
|
"Limit": limit,
|
|
466
470
|
"Recursive": str(recursive).lower(),
|
|
467
|
-
"Fields": ITEM_FIELDS,
|
|
468
|
-
"SortBy":
|
|
469
|
-
"SortOrder":
|
|
471
|
+
"Fields": fields or ITEM_FIELDS,
|
|
472
|
+
"SortBy": sort_by,
|
|
473
|
+
"SortOrder": sort_order,
|
|
470
474
|
}
|
|
471
475
|
if parent_id:
|
|
472
476
|
params["ParentId"] = parent_id
|
|
@@ -493,11 +497,11 @@ class EmbyClient:
|
|
|
493
497
|
break
|
|
494
498
|
return items
|
|
495
499
|
|
|
496
|
-
def get_item_info(self, item_id: str) -> dict:
|
|
500
|
+
def get_item_info(self, item_id: str, *, fields: str | None = None) -> dict:
|
|
497
501
|
uid = self.resolve_user_id()
|
|
498
502
|
resp = self._get(
|
|
499
503
|
f"/Users/{uid}/Items/{item_id}",
|
|
500
|
-
params={"Fields": ITEM_FIELDS},
|
|
504
|
+
params={"Fields": fields or ITEM_FIELDS},
|
|
501
505
|
)
|
|
502
506
|
return resp.json()
|
|
503
507
|
|