plextool 3.0.1__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.
@@ -0,0 +1,232 @@
1
+ Metadata-Version: 2.4
2
+ Name: plextool
3
+ Version: 3.0.1
4
+ Summary: Maintenance helpers for a Plex Media Server
5
+ Author: Milkmansson
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/milkmansson/plextool
8
+ Project-URL: Documentation, https://plextool.readthedocs.io/
9
+ Project-URL: Source, https://github.com/milkmansson/plextool
10
+ Project-URL: Issues, https://github.com/milkmansson/plextool/issues
11
+ Keywords: plex,plex-media-server,plexapi,recently-added,duplicates,watched,subtitles,cli
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Multimedia :: Video
21
+ Classifier: Topic :: System :: Systems Administration
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: plexapi>=4.18
26
+ Requires-Dist: pyjwt[crypto]
27
+ Provides-Extra: qr
28
+ Requires-Dist: segno; extra == "qr"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest; extra == "dev"
31
+ Requires-Dist: ruff; extra == "dev"
32
+ Requires-Dist: segno; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # plextool
36
+
37
+ > [!WARNING]
38
+ > Still in development/testing... please raise an issue if you find one!
39
+
40
+ Command line tools for Plex library maintenance, built on
41
+ [python-plexapi](https://python-plexapi.readthedocs.io/). They talk to the
42
+ server through its API. Nothing here touches the Plex database file, which is
43
+ too risky to edit by hand.
44
+
45
+ ## What it is useful for
46
+
47
+ plextool is a command line toolkit for looking after a Plex Media Server: fixing
48
+ things Plex's web interface can't, and finding problems across a large library.
49
+ Typical jobs:
50
+
51
+ - **Fix the Recently Added order.** This is what it was first built for. Plex has no way to
52
+ edit the Recently Added lists, so after you rebuild the database, delete
53
+ duplicate files and rescan, or reorganise files on disk, everything shows up as
54
+ "new" and the real newest content is buried. [`plextool recent`](https://plextool.readthedocs.io/en/latest/commands/recent.html)
55
+ changes the "added at" date of movies, shows, seasons and episodes: set each
56
+ item back to its own release or air date, shift dates by an offset, or set one date for a
57
+ whole batch. The date is locked so a rescan can't undo it.
58
+ ```console
59
+ $ plextool recent --recent 20 --release # preview: put the 20 newest back to their release dates
60
+ $ plextool recent --title "Some Show" --shift=-30d --commit
61
+ ```
62
+ - **Find and remove duplicate movies and episodes.** [`plextool dupes`](https://plextool.readthedocs.io/en/latest/commands/dupes.html)
63
+ lists every item Plex holds more than one file for, and can delete the extras you don't want.
64
+ - **Free up disk space.** [`plextool stale`](https://plextool.readthedocs.io/en/latest/commands/stale.html) finds large, never-watched or
65
+ long-idle movies and shows.
66
+ - **Audit a library.** [`plextool audit`](https://plextool.readthedocs.io/en/latest/commands/audit.html) reports unmatched items, missing files,
67
+ missing posters or summaries, low-resolution video, and missing subtitle or audio languages.
68
+ - **Copy, back up and restore watched status.** [`plextool watched`](https://plextool.readthedocs.io/en/latest/commands/watched.html) moves watched
69
+ state between users (for example when a shared account is split), saves it to a file, and
70
+ restores it after a rebuild or when someone closes and reopens their Plex account.
71
+ - **Clear a stuck Continue Watching list.** [`plextool resume`](https://plextool.readthedocs.io/en/latest/commands/resume.html) lists and removes
72
+ entries that won't go away.
73
+ - **Back up and restore playlists.** [`plextool playlists`](https://plextool.readthedocs.io/en/latest/commands/playlists.html) saves video playlists
74
+ to a file and recreates them on the same or another server.
75
+ - **Get subtitles.** [`plextool subs`](https://plextool.readthedocs.io/en/latest/commands/subs.html) extracts the subtitle tracks inside MKV and MP4
76
+ files, searches Plex's subtitle providers for a language and downloads one, and, with
77
+ `--export`, copies the subtitle Plex downloaded out of its database into a file beside
78
+ the video so it works outside Plex too. Plex itself never writes that file.
79
+ - **Script Plex.** Reports can print JSON, and exports can go through a pipe, so the output
80
+ feeds other tools.
81
+
82
+ Everything that changes the server is a preview until you pass `--commit`. plextool uses Plex's API and
83
+ never edits the Plex database file. It signs in through your browser with
84
+ [`plextool auth`](https://plextool.readthedocs.io/en/latest/commands/auth.html), and works against a server on the same machine, across the
85
+ internet, or directly with no internet access ([`plextool server`](https://plextool.readthedocs.io/en/latest/commands/server.html)).
86
+
87
+ ## Commands
88
+
89
+ | Command | What it does |
90
+ | --- | --- |
91
+ | [`plextool auth`](https://plextool.readthedocs.io/en/latest/commands/auth.html) | Sign in to Plex with a link or QR code, list and remove old sign-ins from your account, and wipe the saved login and keys. |
92
+ | [`plextool server`](https://plextool.readthedocs.io/en/latest/commands/server.html) | Find servers on your account or network and choose the one to use. Covers working offline or directly against the server. |
93
+ | [`plextool status`](https://plextool.readthedocs.io/en/latest/commands/status.html) | Server version, library sizes, who is watching what. |
94
+ | [`plextool scan`](https://plextool.readthedocs.io/en/latest/commands/scan.html) | Scan libraries or a single folder, refresh metadata, empty trash, optimize. |
95
+ | [`plextool recent`](https://plextool.readthedocs.io/en/latest/commands/recent.html) | Change "added at" dates to reorder Recently Added. Works on movies, shows, seasons and episodes. |
96
+ | [`plextool dupes`](https://plextool.readthedocs.io/en/latest/commands/dupes.html) | List movies and episodes that have more than one file, and optionally delete the extras. |
97
+ | [`plextool stale`](https://plextool.readthedocs.io/en/latest/commands/stale.html) | Find large, unwatched or long-idle content to free up space. |
98
+ | [`plextool audit`](https://plextool.readthedocs.io/en/latest/commands/audit.html) | Find unmatched items, missing files, missing posters or summaries, low resolution, missing subtitle or audio languages. |
99
+ | [`plextool watched`](https://plextool.readthedocs.io/en/latest/commands/watched.html) | Copy watched state between users, back it up and restore it, or mark a show or movie watched. |
100
+ | [`plextool resume`](https://plextool.readthedocs.io/en/latest/commands/resume.html) | List or clear stuck Continue Watching entries. |
101
+ | [`plextool playlists`](https://plextool.readthedocs.io/en/latest/commands/playlists.html) | Back up and restore video playlists. |
102
+ | [`plextool subs`](https://plextool.readthedocs.io/en/latest/commands/subs.html) | Extract subtitles from MKV and MP4 files, search Plex's subtitle providers for new ones and pick which to download, and copy subtitles Plex downloaded (kept in its database, not beside the video) out as files next to the video. Files are named for Plex, forced and SDH included. |
103
+
104
+ The `plextool` commands that change anything do a dry run unless you pass
105
+ `--commit`. Deleting files (`dupes --keep`) also asks you to type `DELETE`.
106
+
107
+ ## Quick start
108
+
109
+ Install it from PyPI. This needs `python` installed as a prerequisite:
110
+
111
+ ```console
112
+ $ python3 -m venv .venv && source .venv/bin/activate # optional: keeps plextool's packages separate
113
+ $ pip install 'plextool[qr]' # '[qr]' adds a QR code to the sign-in; leave it off if you don't want one
114
+ $ plextool auth login # open the link it prints (or scan the QR code) and approve
115
+ $ plextool server find # servers on your Plex account and on your network
116
+ $ plextool server use "My Server" # one of the names from the list
117
+ $ plextool status # libraries, and who is watching what right now
118
+ ```
119
+
120
+ `status` ends with what is playing:
121
+
122
+ ```console
123
+ Now playing (1 session, 0 transcoding)
124
+ alice: Some Movie (2020) [playing] on Living Room TV
125
+ ```
126
+
127
+ To get, say, Swedish subtitles for that movie from the subtitle providers Plex searches:
128
+
129
+ ```console
130
+ $ plextool subs fetch -t "Some Movie" --lang sv --list # see what is available; nothing is downloaded
131
+ $ plextool subs fetch -t "Some Movie" --lang sv --choose --commit # pick one; Plex downloads it
132
+ $ plextool subs fetch -t "Some Movie" --lang sv --choose --export --commit # same, and also save a file beside the video
133
+ ```
134
+
135
+ **Where the subtitle ends up.** When Plex downloads a subtitle from a provider, it keeps
136
+ the copy in its own database. It does not put a file next to the video, so only Plex can
137
+ show it: another player, or another Plex server, never sees it. The first two commands stop
138
+ there, and you pick the subtitle from the player's subtitle menu.
139
+
140
+ **`--export` gets around that.** Once Plex has downloaded the subtitle, plextool copies
141
+ Plex's stored copy out of the server and saves it as an ordinary file beside the video
142
+ (`<video name>.sv.srt`), which any player can use. It doesn't read the video file, so the
143
+ MKV or MP4 is never opened, and it doesn't contact the subtitle provider. (Subtitle
144
+ tracks that are already inside an MKV or MP4 are a different job, for `plextool subs extract`.)
145
+ For `--export`, the machine you run it on must be able to read the media files. If it sees
146
+ them under a different path than Plex does, use `--map`. The
147
+ [`subs` page](https://plextool.readthedocs.io/en/latest/commands/subs.html#where-each-subtitle-comes-from) sets out where each kind of subtitle comes from.
148
+
149
+ For a TV show, `-t "Some Show"` covers every episode, which is a search for each one,
150
+ so start with `--list`.
151
+
152
+ If the server is on the machine you are typing on, skip `server find` and `server use`:
153
+ plextool tries `http://localhost:32400` by default. Without internet access, see
154
+ [working offline](https://plextool.readthedocs.io/en/latest/commands/server.html#working-offline-or-directly-against-the-server).
155
+
156
+ ## Getting help
157
+
158
+ Every command explains itself, with options and examples:
159
+
160
+ ```console
161
+ $ plextool --help
162
+ $ plextool recent --help
163
+ $ plextool watched copy --help
164
+ ```
165
+
166
+ A fuller page for each command is on [Read the Docs](https://plextool.readthedocs.io/)
167
+ (linked in the table above); its source is in `docs/source/commands/`.
168
+
169
+ ## Install
170
+
171
+ plextool is tested on Python 3.12. It declares Python 3.9 or later, so pip will
172
+ install it on older versions. If something doesn't work on one, please
173
+ [open an issue](https://github.com/milkmansson/plextool/issues) with your Python
174
+ version.
175
+
176
+ `plextool subs` also needs MKVToolNix (`mkvmerge`, `mkvextract`) for MKV files and
177
+ FFmpeg (`ffmpeg`, `ffprobe`) for MP4 files. You only need the ones for the file types
178
+ you use.
179
+
180
+ ```console
181
+ $ pip install plextool # installs the `plextool` command
182
+ $ plextool --help
183
+ ```
184
+
185
+ To install from a checkout instead (this needs `git`):
186
+
187
+ ```console
188
+ $ git clone https://github.com/milkmansson/plextool.git
189
+ $ cd plextool
190
+ $ pip install .
191
+ ```
192
+
193
+ To run from a checkout without installing, `pip install -r requirements.txt`
194
+ and use `python3 -m plextool ...` instead.
195
+
196
+ ## Connecting
197
+
198
+ Sign in once. This prints a link (and a QR code, if `segno` is installed) to
199
+ approve in a browser:
200
+
201
+ ```console
202
+ $ plextool auth login
203
+ $ plextool server find # skip if the server is on this machine
204
+ $ plextool server use "My Server" # or: server use http://myserver:32400
205
+ ```
206
+
207
+ Without a saved choice, plextool uses `http://localhost:32400`, or `$PLEX_URL`
208
+ or `--base-url` if given. [`plextool server`](https://plextool.readthedocs.io/en/latest/commands/server.html) explains the
209
+ options, including working with no internet or directly on the server's machine.
210
+
211
+ That saves a Plex token in `~/.config/plextool/` (readable only by you).
212
+ [`plextool auth`](https://plextool.readthedocs.io/en/latest/commands/auth.html) explains exactly what is kept, how to wipe it
213
+ with `plextool auth wipe`, and `--type jwt`, a short-lived token that plex.tv
214
+ accepts but Plex Media Server doesn't yet.
215
+
216
+ If you would rather supply your own [Plex token](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/),
217
+ plextool looks for one in this order: `--token`, `--token-file FILE` (`-` for
218
+ standard input), `$PLEX_TOKEN`, the output of `$PLEX_TOKEN_CMD`, then the saved
219
+ login. Prefer `--token-file` or the environment to `--token`, which leaves the
220
+ token in your shell history.
221
+
222
+ ## Development
223
+
224
+ ```console
225
+ $ pip install -e '.[dev]'
226
+ $ pytest
227
+ ```
228
+
229
+ ## Disclaimer
230
+
231
+ These tools only use the documented plexapi calls, but they do write to your
232
+ server when you pass `--commit`. Check the dry run first. Use at your own risk.
@@ -0,0 +1,23 @@
1
+ plextool/__init__.py,sha256=qrpkFabDf2NYU-ptuPLIArmAZH8SOk28swf_g1R0i0E,109
2
+ plextool/__main__.py,sha256=E6Gls0DNz8GQK2K-kOUIx8cYhgANW_CH54VKrfCfs14,52
3
+ plextool/audit.py,sha256=d8JfAMEzvP2RtA0K2A2Lv-S5oRq9s7hx9h45XAuhjSs,5279
4
+ plextool/auth.py,sha256=h3w7Rrl42dZoymhIfLPs3OwflDmhklSLdRh6NIPxxpU,22228
5
+ plextool/cli.py,sha256=QxAd-yS6mGUUn4lCmi6ETJ_jdTbgBEbxV_uqy7bY6jQ,1563
6
+ plextool/common.py,sha256=WJuXW_uIOMTkMrUZSLkYxy3reOfZI402x9-emvz28vk,10703
7
+ plextool/dupes.py,sha256=ueoK28fJh7NB6bNXKjTn2dz4WYtXLuRkuv1jR-SaR3A,8113
8
+ plextool/ondemand.py,sha256=-25NqJacsRRoLynepVck6m7NjhEmOfihpg2UXmtIAnw,17404
9
+ plextool/playlists.py,sha256=vmy8a3Ao49q49MDhJrKyCQVMO9_BUn6jbpDcwIpuPXo,6414
10
+ plextool/recent.py,sha256=B6sDVvYFkL9Rg54ksq_I2kxg52keF6HUjWanAqpvmuo,9231
11
+ plextool/resume.py,sha256=HOnXCzGv3kWPINg3mB03jU0WSQBTN1vnbiUXdQYS4_A,2712
12
+ plextool/scan.py,sha256=4riXtzRovDUpKNCjiRMKH7FM9AOoyEun0Fu7-hj7DCo,3177
13
+ plextool/server.py,sha256=LfI1Ng0qp0mxPTcRmbPOd3DexIM6oY96bM7KUl_LT9c,19167
14
+ plextool/stale.py,sha256=zyyxGLSlD6zPzp2D_jGTv-kBsjBu4r6k1wa1xQXpg0o,5276
15
+ plextool/status.py,sha256=NTG3bCy5KNEcPEAcbJ05Cxct42-pDSfHB-R6Ay8oDi0,2506
16
+ plextool/subs.py,sha256=Tt2Tz4mJw2epurYasaeIABkTS8uPS5UPOSBGHULPKx4,13953
17
+ plextool/watched.py,sha256=bXZex73PKKm_5fNsfCdfwYo-TN-DKujNjOqe-pXO7s0,11234
18
+ plextool-3.0.1.dist-info/licenses/LICENSE,sha256=s4q4SyOs-lvLr8kiGt6iWnCgk2as6DFbkrKoWrmimmE,1068
19
+ plextool-3.0.1.dist-info/METADATA,sha256=0I6q-IOCzWW8_wY-VgFT_bxMAI_ikOdcah-O3Lo3fnk,12915
20
+ plextool-3.0.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
21
+ plextool-3.0.1.dist-info/entry_points.txt,sha256=ukEoR9SZOXJCjkbAP5ndx5a49GmHs_VQ8J9CXhvTqlA,47
22
+ plextool-3.0.1.dist-info/top_level.txt,sha256=e0C-lq1W8fAGnrFUgT_KNF5LF_Q84-oHnZoPNtrJGJY,9
23
+ plextool-3.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ plextool = plextool.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Milkmansson
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 @@
1
+ plextool