emby-cli 0.1.1__tar.gz → 0.2.2__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.2.2/CHANGELOG.md +22 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/PKG-INFO +10 -1
- {emby_cli-0.1.1 → emby_cli-0.2.2}/README.md +9 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/_version.py +2 -2
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/cli.py +39 -6
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/client.py +345 -73
- emby_cli-0.2.2/src/emby_cli/commands/batch.py +158 -0
- emby_cli-0.2.2/src/emby_cli/commands/download.py +71 -0
- emby_cli-0.2.2/src/emby_cli/commands/info.py +125 -0
- emby_cli-0.2.2/src/emby_cli/commands/list.py +50 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/commands/play.py +5 -4
- emby_cli-0.2.2/src/emby_cli/commands/search.py +30 -0
- emby_cli-0.2.2/src/emby_cli/commands/sync.py +46 -0
- emby_cli-0.2.2/src/emby_cli/commands/version.py +35 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/constants.py +5 -0
- emby_cli-0.2.2/src/emby_cli/download_ops.py +136 -0
- emby_cli-0.2.2/src/emby_cli/output.py +79 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/resolve.py +111 -33
- emby_cli-0.2.2/tests/test_client.py +102 -0
- emby_cli-0.2.2/tests/test_info.py +105 -0
- emby_cli-0.2.2/tests/test_output.py +19 -0
- emby_cli-0.2.2/tests/test_parser.py +80 -0
- emby_cli-0.2.2/tests/test_resolve_table.py +42 -0
- emby_cli-0.2.2/tests/test_version.py +127 -0
- emby_cli-0.1.1/CHANGELOG.md +0 -5
- emby_cli-0.1.1/src/emby_cli/commands/batch.py +0 -244
- emby_cli-0.1.1/src/emby_cli/commands/download.py +0 -77
- emby_cli-0.1.1/src/emby_cli/commands/list.py +0 -35
- emby_cli-0.1.1/src/emby_cli/commands/search.py +0 -31
- emby_cli-0.1.1/src/emby_cli/commands/sync.py +0 -54
- emby_cli-0.1.1/src/emby_cli/download_ops.py +0 -47
- emby_cli-0.1.1/tests/test_parser.py +0 -32
- {emby_cli-0.1.1 → emby_cli-0.2.2}/.env.example +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/.github/workflows/ci.yml +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/.github/workflows/publish.yml +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/.gitignore +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/LICENSE +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/pyproject.toml +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/__init__.py +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/__main__.py +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/commands/__init__.py +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/util.py +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/src/emby_cli/version.py +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/tests/test_resolve.py +0 -0
- {emby_cli-0.1.1 → emby_cli-0.2.2}/tests/test_util.py +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.2.2
|
|
6
|
+
|
|
7
|
+
- `version`: show emby-cli version; with valid server credentials also show Emby `/System/Info` version.
|
|
8
|
+
- `info`: session summary (user, url, server, version, os, id) plus library names and item counts from `GET /Items/Counts` (replaces draft `whoami`).
|
|
9
|
+
- `--pick-best-item` is a flag (presence enables auto-select); no longer takes `0`/`1`.
|
|
10
|
+
- `info` / `version` probe the server once (no retries); on failure show configured user/URL and mark server name/version as not validated.
|
|
11
|
+
- Note: `/Items/Counts` may count multiple versions of the same title higher than UI “items” views.
|
|
12
|
+
- `probe_session`: fall back to `/System/Info/Public` when full `/System/Info` is forbidden (non-admin users); still proceed with Views/Counts.
|
|
13
|
+
- Avoid broken `/Users/Me` on some Emby servers (HTTP 500 Guid format): use `User` from authenticate or `/Users/{id}`.
|
|
14
|
+
- `list`: library table is ID/Name/Type/Items (no Year/Res); gather all counts before printing; `list -l` keeps media table like `search`.
|
|
15
|
+
|
|
16
|
+
## 0.2.0
|
|
17
|
+
|
|
18
|
+
- API fixes: `get_item_info` Fields, `/Users/Me`, safer 416 resume, `api_key` on play URLs, client version from package, `/emby` base URL normalize, HLS without invalid `copy` codecs, paginated episodes.
|
|
19
|
+
- Shared resolve for `play`/`batch` (strict by default; `--pick-best-item` flag).
|
|
20
|
+
- Homogeneous CLI messages (`output.py`); shared library/download loops; non-zero exit on errors / batch not-found.
|
|
21
|
+
- `search`: paginate Emby results (was capped at 25); `--count` / `-n` to limit how many to return (default: all).
|
|
22
|
+
- More tests (`test_client`, `test_output`, parser coverage).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: emby-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: CLI to list, search, play, and download/backup original media from an Emby server via its REST API.
|
|
5
5
|
Project-URL: Homepage, https://github.com/soukron/emby-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/soukron/emby-cli
|
|
@@ -70,14 +70,23 @@ See `.env.example`. The app does not load `.env` itself — `source` it or expor
|
|
|
70
70
|
## Usage
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
+
emby-cli version
|
|
74
|
+
emby-cli info
|
|
73
75
|
emby-cli list
|
|
74
76
|
emby-cli search "Title"
|
|
77
|
+
emby-cli search "Title" --count 50
|
|
75
78
|
emby-cli download -i <itemId> -o ./downloads
|
|
76
79
|
emby-cli sync -l "Movies"
|
|
77
80
|
emby-cli batch -F titles.txt -n
|
|
81
|
+
emby-cli batch -F titles.txt --pick-best-item
|
|
78
82
|
emby-cli play "Movie (2010)"
|
|
83
|
+
emby-cli play "Show S01E01" --pick-best-item
|
|
79
84
|
```
|
|
80
85
|
|
|
86
|
+
`info` reports libraries and totals from `GET /Items/Counts` (totals may include multiple versions of the same title).
|
|
87
|
+
|
|
88
|
+
Title resolution (`play` / `batch`) is **strict** by default (year mismatch or multiple matches fail that line). Pass `--pick-best-item` to auto-select the best ≤1080p version. In `batch`, a season line like `Show S01` downloads the whole season (with the same pick-best rule per episode version).
|
|
89
|
+
|
|
81
90
|
Download methods (`-m` / `EMBY_METHOD`):
|
|
82
91
|
|
|
83
92
|
- `download` — `GET /Items/{id}/Download`
|
|
@@ -36,14 +36,23 @@ See `.env.example`. The app does not load `.env` itself — `source` it or expor
|
|
|
36
36
|
## Usage
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
+
emby-cli version
|
|
40
|
+
emby-cli info
|
|
39
41
|
emby-cli list
|
|
40
42
|
emby-cli search "Title"
|
|
43
|
+
emby-cli search "Title" --count 50
|
|
41
44
|
emby-cli download -i <itemId> -o ./downloads
|
|
42
45
|
emby-cli sync -l "Movies"
|
|
43
46
|
emby-cli batch -F titles.txt -n
|
|
47
|
+
emby-cli batch -F titles.txt --pick-best-item
|
|
44
48
|
emby-cli play "Movie (2010)"
|
|
49
|
+
emby-cli play "Show S01E01" --pick-best-item
|
|
45
50
|
```
|
|
46
51
|
|
|
52
|
+
`info` reports libraries and totals from `GET /Items/Counts` (totals may include multiple versions of the same title).
|
|
53
|
+
|
|
54
|
+
Title resolution (`play` / `batch`) is **strict** by default (year mismatch or multiple matches fail that line). Pass `--pick-best-item` to auto-select the best ≤1080p version. In `batch`, a season line like `Show S01` downloads the whole season (with the same pick-best rule per episode version).
|
|
55
|
+
|
|
47
56
|
Download methods (`-m` / `EMBY_METHOD`):
|
|
48
57
|
|
|
49
58
|
- `download` — `GET /Items/{id}/Download`
|
|
@@ -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.2.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 2)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -15,13 +15,21 @@ import requests
|
|
|
15
15
|
from emby_cli.client import EmbyClient
|
|
16
16
|
from emby_cli.commands.batch import cmd_batch
|
|
17
17
|
from emby_cli.commands.download import cmd_download
|
|
18
|
+
from emby_cli.commands.info import cmd_info
|
|
18
19
|
from emby_cli.commands.list import cmd_list
|
|
19
20
|
from emby_cli.commands.play import cmd_play
|
|
20
21
|
from emby_cli.commands.search import cmd_search
|
|
21
22
|
from emby_cli.commands.sync import cmd_sync
|
|
23
|
+
from emby_cli.commands.version import cmd_version
|
|
22
24
|
from emby_cli.constants import DEFAULT_OUTPUT
|
|
23
25
|
|
|
24
26
|
|
|
27
|
+
_FORCE_HELP = (
|
|
28
|
+
"Re-download even if local file matches remote size "
|
|
29
|
+
"(or HLS .mkv + .done marker exists)"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
25
33
|
def build_parser() -> argparse.ArgumentParser:
|
|
26
34
|
env = os.environ.get
|
|
27
35
|
|
|
@@ -44,7 +52,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
44
52
|
dl.add_argument("--item-id", "-i", default=env("EMBY_ITEM_ID"), help="Specific item ID to download (env: EMBY_ITEM_ID)")
|
|
45
53
|
dl.add_argument("--output", "-o", default=env("EMBY_OUTPUT", DEFAULT_OUTPUT),
|
|
46
54
|
help=f"Output directory (env: EMBY_OUTPUT, default: {DEFAULT_OUTPUT})")
|
|
47
|
-
dl.add_argument("--force", "-f", action="store_true", help=
|
|
55
|
+
dl.add_argument("--force", "-f", action="store_true", help=_FORCE_HELP)
|
|
48
56
|
dl.add_argument("--throttle", "-t", type=float, nargs="?", const=1.0, default=0,
|
|
49
57
|
help="Limit speed to playback rate. Optional multiplier: 1=realtime, 1.5=50%% faster (default: off)")
|
|
50
58
|
dl.add_argument("--method", "-m", default=env("EMBY_METHOD", "download"),
|
|
@@ -54,6 +62,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
54
62
|
|
|
55
63
|
sr = sub.add_parser("search", help="Search for items by name")
|
|
56
64
|
sr.add_argument("query", help="Search query")
|
|
65
|
+
sr.add_argument(
|
|
66
|
+
"--count", "-n",
|
|
67
|
+
type=int,
|
|
68
|
+
default=None,
|
|
69
|
+
metavar="N",
|
|
70
|
+
help="Max results to return (default: all, paginated)",
|
|
71
|
+
)
|
|
57
72
|
|
|
58
73
|
pl = sub.add_parser("play", help="Play an item via DirectStreamUrl in an external player")
|
|
59
74
|
pl.add_argument("query", nargs="?",
|
|
@@ -65,15 +80,15 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
65
80
|
"/Applications/VLC.app/Contents/MacOS/VLC")
|
|
66
81
|
pl.add_argument("--wait", action="store_true",
|
|
67
82
|
help="Block until the player process exits (default: detach and return)")
|
|
68
|
-
pl.add_argument("--pick-best-item",
|
|
69
|
-
help="On ambiguous search results
|
|
70
|
-
"
|
|
83
|
+
pl.add_argument("--pick-best-item", action="store_true",
|
|
84
|
+
help="On ambiguous search results, auto-select best ≤1080p "
|
|
85
|
+
"(default: list matches and fail)")
|
|
71
86
|
|
|
72
87
|
sy = sub.add_parser("sync", help="Sync all libraries (or one with --library)")
|
|
73
88
|
sy.add_argument("--library", "-l", default=env("EMBY_LIBRARY"), help="Specific library to sync (env: EMBY_LIBRARY)")
|
|
74
89
|
sy.add_argument("--output", "-o", default=env("EMBY_OUTPUT", DEFAULT_OUTPUT),
|
|
75
90
|
help=f"Output directory (env: EMBY_OUTPUT, default: {DEFAULT_OUTPUT})")
|
|
76
|
-
sy.add_argument("--force", "-f", action="store_true", help=
|
|
91
|
+
sy.add_argument("--force", "-f", action="store_true", help=_FORCE_HELP)
|
|
77
92
|
sy.add_argument("--throttle", "-t", type=float, nargs="?", const=1.0, default=0,
|
|
78
93
|
help="Limit speed to playback rate. Optional multiplier: 1=realtime, 1.5=50%% faster (default: off)")
|
|
79
94
|
sy.add_argument("--method", "-m", default=env("EMBY_METHOD", "download"),
|
|
@@ -86,13 +101,23 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
86
101
|
ba.add_argument("--dry-run", "-n", action="store_true", help="Search and select only, do not download")
|
|
87
102
|
ba.add_argument("--output", "-o", default=env("EMBY_OUTPUT", DEFAULT_OUTPUT),
|
|
88
103
|
help=f"Output directory (env: EMBY_OUTPUT, default: {DEFAULT_OUTPUT})")
|
|
89
|
-
ba.add_argument("--force", "-f", action="store_true", help=
|
|
104
|
+
ba.add_argument("--force", "-f", action="store_true", help=_FORCE_HELP)
|
|
90
105
|
ba.add_argument("--throttle", "-t", type=float, nargs="?", const=1.0, default=0,
|
|
91
106
|
help="Limit speed to playback rate. Optional multiplier: 1=realtime, 1.5=50%% faster (default: off)")
|
|
92
107
|
ba.add_argument("--method", "-m", default=env("EMBY_METHOD", "download"),
|
|
93
108
|
choices=["download", "stream", "hls"],
|
|
94
109
|
help="Download method: 'download' (API Download), 'stream' (browser-like original.*), "
|
|
95
110
|
"or 'hls' (stream chunks + remux) (env: EMBY_METHOD)")
|
|
111
|
+
ba.add_argument("--pick-best-item", action="store_true",
|
|
112
|
+
help="On ambiguous search results, auto-select best ≤1080p "
|
|
113
|
+
"(also per episode version in a season; default: fail the line)")
|
|
114
|
+
|
|
115
|
+
sub.add_parser("version", help="Show emby-cli version (and Emby server version if credentials work)")
|
|
116
|
+
sub.add_parser(
|
|
117
|
+
"info",
|
|
118
|
+
help="Show session user, server details, libraries, and item counts "
|
|
119
|
+
"(via /Items/Counts; versions may inflate totals)",
|
|
120
|
+
)
|
|
96
121
|
|
|
97
122
|
return p
|
|
98
123
|
|
|
@@ -101,6 +126,14 @@ def main() -> None:
|
|
|
101
126
|
parser = build_parser()
|
|
102
127
|
args = parser.parse_args()
|
|
103
128
|
|
|
129
|
+
if args.command == "version":
|
|
130
|
+
cmd_version(args)
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
if args.command == "info":
|
|
134
|
+
cmd_info(args)
|
|
135
|
+
return
|
|
136
|
+
|
|
104
137
|
if not args.server:
|
|
105
138
|
parser.error("Provide --server or set EMBY_SERVER")
|
|
106
139
|
|