plexdo 1.1.18__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.
- plexdo/__init__.py +26 -0
- plexdo/__main__.py +24 -0
- plexdo/accounts.py +253 -0
- plexdo/airdates.py +136 -0
- plexdo/cache.py +38 -0
- plexdo/cli.py +157 -0
- plexdo/commands/__init__.py +63 -0
- plexdo/commands/auth.py +201 -0
- plexdo/commands/build.py +194 -0
- plexdo/commands/copy.py +169 -0
- plexdo/commands/libraries.py +231 -0
- plexdo/commands/metadata.py +135 -0
- plexdo/commands/missing.py +234 -0
- plexdo/commands/playlists.py +174 -0
- plexdo/commands/rescan.py +95 -0
- plexdo/commands/search.py +114 -0
- plexdo/commands/status.py +245 -0
- plexdo/commands/stream.py +138 -0
- plexdo/commands/users.py +39 -0
- plexdo/commands/watched.py +295 -0
- plexdo/config.py +153 -0
- plexdo/console.py +240 -0
- plexdo/constants.py +111 -0
- plexdo/convert.py +38 -0
- plexdo/data/_plexdo +359 -0
- plexdo/data/plexdo.1 +571 -0
- plexdo/data/plexdo.bash +597 -0
- plexdo/data/plexdo.fish +317 -0
- plexdo/data/plexdo.ps1 +371 -0
- plexdo/formats.py +181 -0
- plexdo/gallery.py +190 -0
- plexdo/identify.py +75 -0
- plexdo/logs.py +21 -0
- plexdo/m3u.py +34 -0
- plexdo/paths.py +105 -0
- plexdo/photos.py +74 -0
- plexdo/playlists.py +174 -0
- plexdo/py.typed +0 -0
- plexdo/records.py +136 -0
- plexdo/sections.py +58 -0
- plexdo/security.py +65 -0
- plexdo/sorting.py +50 -0
- plexdo/throttle.py +59 -0
- plexdo/titles.py +53 -0
- plexdo/tokens.py +88 -0
- plexdo-1.1.18.dist-info/METADATA +601 -0
- plexdo-1.1.18.dist-info/RECORD +51 -0
- plexdo-1.1.18.dist-info/WHEEL +5 -0
- plexdo-1.1.18.dist-info/entry_points.txt +2 -0
- plexdo-1.1.18.dist-info/licenses/LICENSE +232 -0
- plexdo-1.1.18.dist-info/top_level.txt +1 -0
plexdo/data/_plexdo
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
#compdef plexdo
|
|
2
|
+
# zsh completion for plexdo
|
|
3
|
+
#
|
|
4
|
+
# Installation:
|
|
5
|
+
# Per user: cp _plexdo ~/.local/share/zsh/site-functions/
|
|
6
|
+
# (ensure that directory is in $fpath, then: compinit)
|
|
7
|
+
# System-wide: cp _plexdo /usr/local/share/zsh/site-functions/
|
|
8
|
+
#
|
|
9
|
+
# Completion for user IDs, library IDs, rating keys, playlists, and albums is
|
|
10
|
+
# read from the 15-minute cache under ~/.cache/plexdo that the list commands
|
|
11
|
+
# populate. A stale cache is refreshed in the background so completion never
|
|
12
|
+
# blocks; the values shown come from whatever is cached at that moment.
|
|
13
|
+
|
|
14
|
+
# Some systems ship "python" but not "python3".
|
|
15
|
+
_plexdo_python() {
|
|
16
|
+
if (( $+commands[python3] )); then print -r -- python3; else print -r -- python; fi
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
(( $+functions[_plexdo_cache_dir] )) || _plexdo_cache_dir() {
|
|
20
|
+
# Memoised: this reads the config file to honour [plex] cache_dir, so it
|
|
21
|
+
# should not run once per completion candidate.
|
|
22
|
+
if [[ -z $_plexdo_cache_resolved ]]; then
|
|
23
|
+
typeset -g _plexdo_cache_resolved
|
|
24
|
+
_plexdo_cache_resolved="$("$(_plexdo_python)" - <<'PYCACHE' 2>/dev/null
|
|
25
|
+
import configparser, os
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
if os.name == "nt":
|
|
28
|
+
base = os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA")
|
|
29
|
+
app = Path(base) / "PlexDo" if base else Path.home() / "AppData/Local/PlexDo"
|
|
30
|
+
cfg_path, default = app / "plexdo.ini", app / "Cache"
|
|
31
|
+
else:
|
|
32
|
+
cfg_path = Path("~/.local/etc/plexdo.ini").expanduser()
|
|
33
|
+
default = Path("~/.cache/plexdo").expanduser()
|
|
34
|
+
value = ""
|
|
35
|
+
if cfg_path.exists():
|
|
36
|
+
parser = configparser.ConfigParser(interpolation=None)
|
|
37
|
+
try:
|
|
38
|
+
parser.read(cfg_path, encoding="utf-8")
|
|
39
|
+
value = (parser.get("plex", "cache_dir", fallback="") or "").strip()
|
|
40
|
+
except Exception:
|
|
41
|
+
value = ""
|
|
42
|
+
print(Path(os.path.expandvars(value)).expanduser() if value else default)
|
|
43
|
+
PYCACHE
|
|
44
|
+
)"
|
|
45
|
+
fi
|
|
46
|
+
print -r -- "$_plexdo_cache_resolved"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Return 0 when the cache file exists and is under 15 minutes old.
|
|
50
|
+
_plexdo_cache_fresh() {
|
|
51
|
+
local file=$1 now mtime
|
|
52
|
+
[[ -f $file ]] || return 1
|
|
53
|
+
now=$(date +%s)
|
|
54
|
+
mtime=$(stat -c %Y "$file" 2>/dev/null) || mtime=$(stat -f %m "$file" 2>/dev/null) || return 1
|
|
55
|
+
(( now - mtime < 900 ))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Run a plexdo list command in the background purely for its cache side effect.
|
|
59
|
+
_plexdo_refresh() {
|
|
60
|
+
local prog=${words[1]:-plexdo}
|
|
61
|
+
( "$prog" "$@" >/dev/null 2>&1 & ) 2>/dev/null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Emit "value" or "value:description" lines from a JSON cache file.
|
|
65
|
+
_plexdo_read_cache() {
|
|
66
|
+
local file=$1 field=$2 desc=$3
|
|
67
|
+
[[ -f $file ]] || return
|
|
68
|
+
python3 - "$file" "$field" "$desc" <<'PY' 2>/dev/null
|
|
69
|
+
import json, sys
|
|
70
|
+
path, field, desc = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
71
|
+
try:
|
|
72
|
+
rows = json.load(open(path, encoding="utf-8"))
|
|
73
|
+
except Exception:
|
|
74
|
+
sys.exit(0)
|
|
75
|
+
for row in rows:
|
|
76
|
+
value = str(row.get(field, "")).strip()
|
|
77
|
+
if not value:
|
|
78
|
+
continue
|
|
79
|
+
if desc:
|
|
80
|
+
label = str(row.get(desc, "")).strip().replace(":", " ")
|
|
81
|
+
print(f"{value}:{label}" if label else value)
|
|
82
|
+
else:
|
|
83
|
+
print(value)
|
|
84
|
+
PY
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_plexdo_users() {
|
|
88
|
+
local cache="$(_plexdo_cache_dir)/users.json"
|
|
89
|
+
_plexdo_cache_fresh $cache || _plexdo_refresh list-users
|
|
90
|
+
local -a ids titles
|
|
91
|
+
ids=( '0:admin account' ${(f)"$(_plexdo_read_cache $cache id title)"} )
|
|
92
|
+
titles=( ${(f)"$(_plexdo_read_cache $cache title '')"} )
|
|
93
|
+
_describe -t user-ids 'user id' ids
|
|
94
|
+
[[ -n $titles ]] && _describe -t user-titles 'user title' titles
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
_plexdo_libraries() {
|
|
98
|
+
local cache="$(_plexdo_cache_dir)/libraries.json"
|
|
99
|
+
_plexdo_cache_fresh $cache || _plexdo_refresh list-libraries
|
|
100
|
+
local -a libs titles
|
|
101
|
+
libs=( ${(f)"$(_plexdo_read_cache $cache id title)"} )
|
|
102
|
+
titles=( ${(f)"$(_plexdo_read_cache $cache title '')"} )
|
|
103
|
+
_describe -t library-ids 'library id' libs
|
|
104
|
+
[[ -n $titles ]] && _describe -t library-titles 'library title' titles
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_plexdo_rating_keys() {
|
|
108
|
+
local dir="$(_plexdo_cache_dir)" file lib
|
|
109
|
+
local -a keys
|
|
110
|
+
for file in $dir/titles.*.json(N); do
|
|
111
|
+
if ! _plexdo_cache_fresh $file; then
|
|
112
|
+
lib=${${file:t}#titles.}; lib=${lib%.json}
|
|
113
|
+
_plexdo_refresh list-titles $lib
|
|
114
|
+
fi
|
|
115
|
+
keys+=( ${(f)"$(_plexdo_read_cache $file ratingKey title)"} )
|
|
116
|
+
done
|
|
117
|
+
if (( ! ${#keys} )); then
|
|
118
|
+
_plexdo_refresh list-libraries
|
|
119
|
+
_message 'rating key (run list-titles <library_id> to populate completion)'
|
|
120
|
+
return
|
|
121
|
+
fi
|
|
122
|
+
_describe -t rating-keys 'rating key' keys
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# $1 is the user id or title already typed on the command line.
|
|
126
|
+
_plexdo_playlists() {
|
|
127
|
+
local user=${1:-0} dir="$(_plexdo_cache_dir)"
|
|
128
|
+
local cache="$dir/playlists.${user}.json"
|
|
129
|
+
_plexdo_cache_fresh $cache || _plexdo_refresh list-playlists $user
|
|
130
|
+
local -a names
|
|
131
|
+
names=( ${(f)"$(_plexdo_read_cache $cache title '')"} )
|
|
132
|
+
if (( ${#names} )); then
|
|
133
|
+
_describe -t playlists 'playlist' names
|
|
134
|
+
else
|
|
135
|
+
_message 'playlist title'
|
|
136
|
+
fi
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# Playlists by title or ratingKey, for list-playlist which accepts either.
|
|
140
|
+
_plexdo_playlists_or_keys() {
|
|
141
|
+
local user=${1:-0} cache="$(_plexdo_cache_dir)/playlists.${user}.json"
|
|
142
|
+
_plexdo_cache_fresh $cache || _plexdo_refresh list-playlists $user
|
|
143
|
+
local -a names keys
|
|
144
|
+
names=( ${(f)"$(_plexdo_read_cache $cache title '')"} )
|
|
145
|
+
keys=( ${(f)"$(_plexdo_read_cache $cache ratingKey title)"} )
|
|
146
|
+
[[ -n $names ]] && _describe -t playlists 'playlist' names
|
|
147
|
+
[[ -n $keys ]] && _describe -t playlist-keys 'playlist ratingKey' keys
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Album names, derived from the "Album - Photo" titles cached for a library.
|
|
151
|
+
_plexdo_albums() {
|
|
152
|
+
local lib=${1:-} cache="$(_plexdo_cache_dir)/titles.${lib}.json"
|
|
153
|
+
[[ -z $lib ]] && { _message 'album name'; return }
|
|
154
|
+
_plexdo_cache_fresh $cache || _plexdo_refresh list-titles $lib
|
|
155
|
+
local -a albums
|
|
156
|
+
albums=( ${(fu)"$(_plexdo_read_cache $cache title '' | sed -n 's/ - .*//p')"} )
|
|
157
|
+
if (( ${#albums} )); then
|
|
158
|
+
_describe -t albums 'album' albums
|
|
159
|
+
else
|
|
160
|
+
_message 'album name'
|
|
161
|
+
fi
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# Nth (0-based) positional argument after the subcommand, "" when absent.
|
|
165
|
+
_plexdo_positional() {
|
|
166
|
+
local want=$1 i=2 skip=0 count=0
|
|
167
|
+
for (( i = 2; i <= $#words - 1; i++ )); do
|
|
168
|
+
if (( skip )); then skip=0; continue; fi
|
|
169
|
+
case ${words[i]} in
|
|
170
|
+
--m3u|--album|--sort|--media-type|--library-id|-l|--library|-t|--title|\
|
|
171
|
+
-u|--username|-p|--password|-c|--code|-f|--format|--section|-p|--prefix|--throttle) skip=1; continue ;;
|
|
172
|
+
-*) continue ;;
|
|
173
|
+
esac
|
|
174
|
+
if (( count == want )); then print -r -- ${words[i]}; return; fi
|
|
175
|
+
(( count++ ))
|
|
176
|
+
done
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
_plexdo_commands() {
|
|
180
|
+
local -a cmds
|
|
181
|
+
cmds=(
|
|
182
|
+
'list-libraries:List all Plex libraries'
|
|
183
|
+
'list-titles:List titles in a library'
|
|
184
|
+
'list-library:List titles in a library (alias for list-titles)'
|
|
185
|
+
'list-show:List all episodes in a show'
|
|
186
|
+
'export-titles:Export an entire library to M3U or an HTML gallery'
|
|
187
|
+
'search:Search Plex for titles matching a query'
|
|
188
|
+
'list-users:List all managed/home users'
|
|
189
|
+
'list-playlists:List playlists for a user'
|
|
190
|
+
'list-playlist:List items in a specific playlist'
|
|
191
|
+
'export-playlist:Export an existing playlist to an M3U file'
|
|
192
|
+
'remove-playlist:Delete a playlist from a user'
|
|
193
|
+
'append-playlist:Append items to an existing playlist'
|
|
194
|
+
'show-metadata:Display metadata for a single item'
|
|
195
|
+
'read:Stream a media file to stdout'
|
|
196
|
+
'rescan:Trigger a library rescan or show scan status'
|
|
197
|
+
'status:Show server identity, sessions, users, scans, and tasks'
|
|
198
|
+
'find-missing:Find gaps in episode numbering across every show'
|
|
199
|
+
'build-interleaved:Round-robin interleaved playlist from shows'
|
|
200
|
+
'build-chronological:Date-sorted playlist from shows and movies'
|
|
201
|
+
'build-randomize:Randomize a playlist into a new one'
|
|
202
|
+
'copy-playlist-all-users:Copy a playlist to all managed users'
|
|
203
|
+
'copy-playlist-to-user:Copy a playlist to a specific user'
|
|
204
|
+
'copy-watched:Synchronise watched state between two users'
|
|
205
|
+
'login:Authenticate with plex.tv and save a token'
|
|
206
|
+
'write-config-example:Write a template config file'
|
|
207
|
+
)
|
|
208
|
+
_describe -t commands 'plexdo command' cmds
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
_plexdo_global_opts=(
|
|
212
|
+
'--json[Output machine-readable JSON instead of tables]'
|
|
213
|
+
'--verbose[Print high-level progress to stderr]'
|
|
214
|
+
'--debug[Print detailed internal logs to stderr]'
|
|
215
|
+
'--dry-run[Show what would happen without mutating Plex]'
|
|
216
|
+
'(-W --wide)'{-W,--wide}'[Do not shrink table columns to the terminal width]'
|
|
217
|
+
'--throttle[Seconds between requests in per-item operations; 0 disables]:seconds:'
|
|
218
|
+
'(-h --help)'{-h,--help}'[Show this help message and exit]'
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
_plexdo_subcommand() {
|
|
222
|
+
local m3u='--m3u[Also export an M3U file using Plex server paths]:m3u path:_files'
|
|
223
|
+
local pfx='(-p --prefix)'{-p,--prefix}'[Rewrite exported paths onto this prefix]:prefix:'
|
|
224
|
+
case ${words[1]} in
|
|
225
|
+
list-titles|list-library)
|
|
226
|
+
_arguments $_plexdo_global_opts \
|
|
227
|
+
'--album[Photo libraries only: restrict to one album]:album:{_plexdo_albums $(_plexdo_positional 0)}' \
|
|
228
|
+
'1:library id:_plexdo_libraries'
|
|
229
|
+
;;
|
|
230
|
+
list-show)
|
|
231
|
+
_arguments $_plexdo_global_opts $pfx $m3u '1:show rating key:_plexdo_rating_keys'
|
|
232
|
+
;;
|
|
233
|
+
show-metadata)
|
|
234
|
+
_arguments $_plexdo_global_opts '1:rating key:_plexdo_rating_keys'
|
|
235
|
+
;;
|
|
236
|
+
export-titles)
|
|
237
|
+
_arguments $_plexdo_global_opts $pfx \
|
|
238
|
+
'--sort[Sort order]:order:(alpha date random)' \
|
|
239
|
+
'--album[Photo libraries only: restrict to one album]:album:{_plexdo_albums $(_plexdo_positional 0)}' \
|
|
240
|
+
'1:library id:_plexdo_libraries' \
|
|
241
|
+
'2:output path:_files'
|
|
242
|
+
;;
|
|
243
|
+
search)
|
|
244
|
+
_arguments $_plexdo_global_opts \
|
|
245
|
+
'--media-type[Restrict to one media type]:type:(movie show episode track photo album artist)' \
|
|
246
|
+
'--library-id[Restrict to one library]:library id:_plexdo_libraries' \
|
|
247
|
+
'1:user:_plexdo_users' \
|
|
248
|
+
'2:query:'
|
|
249
|
+
;;
|
|
250
|
+
status)
|
|
251
|
+
_arguments $_plexdo_global_opts \
|
|
252
|
+
'--section[Show only one section]:section:(server sessions users accounts connections scans activities tasks)'
|
|
253
|
+
;;
|
|
254
|
+
list-users|list-libraries|write-config-example)
|
|
255
|
+
_arguments $_plexdo_global_opts
|
|
256
|
+
;;
|
|
257
|
+
list-playlists)
|
|
258
|
+
_arguments $_plexdo_global_opts '1:user:_plexdo_users'
|
|
259
|
+
;;
|
|
260
|
+
list-playlist)
|
|
261
|
+
_arguments $_plexdo_global_opts $pfx $m3u \
|
|
262
|
+
'1:user:_plexdo_users' \
|
|
263
|
+
'2:playlist:{_plexdo_playlists_or_keys $(_plexdo_positional 0)}'
|
|
264
|
+
;;
|
|
265
|
+
export-playlist)
|
|
266
|
+
_arguments $_plexdo_global_opts $pfx \
|
|
267
|
+
'1:user:_plexdo_users' \
|
|
268
|
+
'2:playlist:{_plexdo_playlists_or_keys $(_plexdo_positional 0)}' \
|
|
269
|
+
'3:output path:_files'
|
|
270
|
+
;;
|
|
271
|
+
remove-playlist)
|
|
272
|
+
_arguments $_plexdo_global_opts \
|
|
273
|
+
'1:user:_plexdo_users' \
|
|
274
|
+
'2:playlist:{_plexdo_playlists_or_keys $(_plexdo_positional 0)}'
|
|
275
|
+
;;
|
|
276
|
+
append-playlist)
|
|
277
|
+
_arguments $_plexdo_global_opts \
|
|
278
|
+
'1:user:_plexdo_users' \
|
|
279
|
+
'2:playlist:{_plexdo_playlists_or_keys $(_plexdo_positional 0)}' \
|
|
280
|
+
'*:rating key:_plexdo_rating_keys'
|
|
281
|
+
;;
|
|
282
|
+
read)
|
|
283
|
+
_arguments $_plexdo_global_opts \
|
|
284
|
+
'1:library id:_plexdo_libraries' \
|
|
285
|
+
'2:rating key:_plexdo_rating_keys'
|
|
286
|
+
;;
|
|
287
|
+
find-missing)
|
|
288
|
+
_arguments $_plexdo_global_opts \
|
|
289
|
+
'(-l --library)'{-l,--library}'[Library to look in]:library:_plexdo_libraries' \
|
|
290
|
+
'(-A --all)'{-A,--all}'[Check every show]' \
|
|
291
|
+
'(-s --season)'{-s,--season}'[Season number, or several comma separated]:seasons:' \
|
|
292
|
+
'--include-specials[Also check season 0]' \
|
|
293
|
+
'1:show:_plexdo_rating_keys'
|
|
294
|
+
;;
|
|
295
|
+
rescan)
|
|
296
|
+
_arguments $_plexdo_global_opts \
|
|
297
|
+
'(-s --status)'{-s,--status}'[Print all active scan jobs]' \
|
|
298
|
+
'(-n --now)'{-n,--now}'[Cancel pending scans before rescanning]' \
|
|
299
|
+
'1:library id:_plexdo_libraries'
|
|
300
|
+
;;
|
|
301
|
+
build-interleaved|build-chronological)
|
|
302
|
+
_arguments $_plexdo_global_opts $pfx $m3u \
|
|
303
|
+
'(-o --overwrite)'{-o,--overwrite}'[Replace an existing playlist of the same name]' \
|
|
304
|
+
'1:playlist name:' \
|
|
305
|
+
'*:rating key:_plexdo_rating_keys'
|
|
306
|
+
;;
|
|
307
|
+
build-randomize)
|
|
308
|
+
_arguments $_plexdo_global_opts $pfx $m3u \
|
|
309
|
+
'(-o --overwrite)'{-o,--overwrite}'[Replace an existing playlist of the same name]' \
|
|
310
|
+
'1:user:_plexdo_users' \
|
|
311
|
+
'2:source playlist:{_plexdo_playlists_or_keys $(_plexdo_positional 0)}' \
|
|
312
|
+
'3:destination playlist:'
|
|
313
|
+
;;
|
|
314
|
+
copy-playlist-all-users)
|
|
315
|
+
_arguments $_plexdo_global_opts \
|
|
316
|
+
'(-o --overwrite)'{-o,--overwrite}'[Overwrite an existing playlist of the same name]' \
|
|
317
|
+
'1:source user:_plexdo_users' \
|
|
318
|
+
'2:source playlist:{_plexdo_playlists_or_keys $(_plexdo_positional 0)}'
|
|
319
|
+
;;
|
|
320
|
+
copy-playlist-to-user)
|
|
321
|
+
_arguments $_plexdo_global_opts \
|
|
322
|
+
'(-o --overwrite)'{-o,--overwrite}'[Overwrite an existing playlist of the same name]' \
|
|
323
|
+
'1:source user:_plexdo_users' \
|
|
324
|
+
'2:source playlist:{_plexdo_playlists_or_keys $(_plexdo_positional 0)}' \
|
|
325
|
+
'3:target user:_plexdo_users' \
|
|
326
|
+
'4:destination playlist:'
|
|
327
|
+
;;
|
|
328
|
+
copy-watched)
|
|
329
|
+
_arguments $_plexdo_global_opts \
|
|
330
|
+
'(-1 --one-way)'{-1,--one-way}'[Only write to the second user]' \
|
|
331
|
+
'(-l --library)'{-l,--library}'[Restrict to one library]:library id:_plexdo_libraries' \
|
|
332
|
+
'(-t --title)'{-t,--title}'[Restrict to one item]:rating key:_plexdo_rating_keys' \
|
|
333
|
+
'--unwatch[Propagate the unwatched state instead]' \
|
|
334
|
+
'1:first user:_plexdo_users' \
|
|
335
|
+
'2:second user:_plexdo_users'
|
|
336
|
+
;;
|
|
337
|
+
login)
|
|
338
|
+
_arguments $_plexdo_global_opts \
|
|
339
|
+
'(-u --username)'{-u,--username}'[Plex username or email]:username:' \
|
|
340
|
+
'(-p --password)'{-p,--password}'[Plex password (INSECURE: visible in ps and shell history)]:password:' \
|
|
341
|
+
'(-c --code)'{-c,--code}'[Two-factor authentication code]:code:' \
|
|
342
|
+
'(-2 --two-factor)'{-2,--two-factor}'[Prompt for a two-factor code]'
|
|
343
|
+
;;
|
|
344
|
+
*)
|
|
345
|
+
_arguments $_plexdo_global_opts
|
|
346
|
+
;;
|
|
347
|
+
esac
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
_plexdo() {
|
|
351
|
+
local curcontext="$curcontext" state line
|
|
352
|
+
typeset -A opt_args
|
|
353
|
+
_arguments -C $_plexdo_global_opts \
|
|
354
|
+
'1:command:_plexdo_commands' \
|
|
355
|
+
'*::command argument:->subcmd'
|
|
356
|
+
[[ $state == subcmd ]] && _plexdo_subcommand
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
_plexdo "$@"
|