plexutil 3.3.1__tar.gz → 3.4.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.
- {plexutil-3.3.1 → plexutil-3.4.0}/PKG-INFO +1 -1
- {plexutil-3.3.1 → plexutil-3.4.0}/pyproject.toml +1 -1
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/__main__.py +37 -3
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/auth.py +4 -8
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/library.py +1 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/prompt.py +16 -6
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/user_request.py +1 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/util/icons.py +3 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil.egg-info/PKG-INFO +1 -1
- {plexutil-3.3.1 → plexutil-3.4.0}/.github/workflows/python-publish.yml +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/.gitignore +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/LICENSE +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/MANIFEST.in +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/README.md +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/git-hooks/commit-msg +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/git-hooks/pre-commit +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/init.sh +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/requirements.txt +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/ruff.toml +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/setup.cfg +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/config/log_config.yaml +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/library_factory.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/movie_library.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/music_library.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/music_playlist.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/core/tv_library.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/bootstrap_paths_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/dropdown_item_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/library_setting_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/movie_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/music_playlist_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/song_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/tv_episode_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/dto/tv_series_dto.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/agent.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/file_type.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/language.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/library_setting.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/library_type.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/scanner.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/enums/server_setting.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/auth_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/bootstrap_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/database_connection_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/device_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/entity_not_found_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/library_illegal_state_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/library_op_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/library_poll_timeout_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/library_section_missing_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/library_unsupported_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/plex_media_missing_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/server_connection_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/unexpected_argument_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/unexpected_naming_pattern_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/exception/user_error.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/graphical/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/graphical/selection_window.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/mapper/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/mapper/music_playlist_mapper.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/mapper/song_mapper.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/model/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/model/music_playlist_entity.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/model/song_entity.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/model/song_music_playlist_entity.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/plex_util_logger.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/service/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/service/db_manager.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/service/music_playlist_service.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/service/song_music_playlist_composite_service.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/service/song_service.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/static.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/util/__init__.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/util/file_importer.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/util/plex_ops.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/util/query_builder.py +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil.egg-info/SOURCES.txt +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil.egg-info/dependency_links.txt +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil.egg-info/entry_points.txt +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil.egg-info/requires.txt +0 -0
- {plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil.egg-info/top_level.txt +0 -0
|
@@ -38,7 +38,7 @@ def main() -> None:
|
|
|
38
38
|
bootstrap_paths_dto = FileImporter.bootstrap()
|
|
39
39
|
user_request = Prompt.confirm_user_request()
|
|
40
40
|
try:
|
|
41
|
-
|
|
41
|
+
plex_account = Auth.get_account(bootstrap_paths_dto)
|
|
42
42
|
except Unauthorized:
|
|
43
43
|
description = f"{Icons.WARNING} Reauthentication required\n"
|
|
44
44
|
PlexUtilLogger.get_logger().warning(description)
|
|
@@ -46,12 +46,46 @@ def main() -> None:
|
|
|
46
46
|
bootstrap_paths_dto.private_key_dir.unlink(missing_ok=True)
|
|
47
47
|
bootstrap_paths_dto.public_key_dir.unlink(missing_ok=True)
|
|
48
48
|
bootstrap_paths_dto.token_dir.unlink(missing_ok=True)
|
|
49
|
-
|
|
49
|
+
plex_account = Auth.get_account(bootstrap_paths_dto)
|
|
50
50
|
|
|
51
|
-
plex_server = Prompt.confirm_server(
|
|
51
|
+
plex_server = Prompt.confirm_server(plex_account=plex_account)
|
|
52
|
+
|
|
53
|
+
release = plex_server.checkForUpdate()
|
|
54
|
+
current_version = plex_server.version
|
|
55
|
+
|
|
56
|
+
if release and user_request is not UserRequest.CHANGELOG:
|
|
57
|
+
release_version = release.version
|
|
58
|
+
description = (
|
|
59
|
+
f"{Icons.WARNING} A Server update is available: "
|
|
60
|
+
f"{release_version} (Current: {current_version})\n"
|
|
61
|
+
f"plexutil changelog (to display changes)"
|
|
62
|
+
)
|
|
63
|
+
PlexUtilLogger.get_logger().warning(description)
|
|
52
64
|
|
|
53
65
|
if user_request is UserRequest.SETTINGS:
|
|
54
66
|
PlexOps.set_server_settings(plex_server=plex_server)
|
|
67
|
+
elif user_request is UserRequest.CHANGELOG:
|
|
68
|
+
if release:
|
|
69
|
+
release_version = release.version
|
|
70
|
+
added = release.added
|
|
71
|
+
fixed = release.fixed
|
|
72
|
+
|
|
73
|
+
description = (
|
|
74
|
+
f"{Icons.BANNER_LEFT}{release_version}{Icons.BANNER_RIGHT}\n"
|
|
75
|
+
f"{Icons.BANNER_LEFT}\nADDED\n{Icons.BANNER_LEFT}\n"
|
|
76
|
+
f"{added}\n"
|
|
77
|
+
f"{Icons.BANNER_LEFT}\nFIXED\n{Icons.BANNER_LEFT}\n"
|
|
78
|
+
f"{fixed}"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
else:
|
|
82
|
+
description = (
|
|
83
|
+
f"{Icons.SUCCESS} Server is up-to-date ({current_version})"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
PlexUtilLogger.get_logger().info(description)
|
|
87
|
+
sys.exit(0)
|
|
88
|
+
|
|
55
89
|
else:
|
|
56
90
|
library = LibraryFactory.get(
|
|
57
91
|
user_request=user_request,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import uuid
|
|
2
2
|
from importlib.metadata import PackageNotFoundError, version
|
|
3
3
|
|
|
4
|
-
from plexapi.myplex import MyPlexAccount, MyPlexJWTLogin
|
|
4
|
+
from plexapi.myplex import MyPlexAccount, MyPlexJWTLogin
|
|
5
5
|
|
|
6
6
|
from plexutil.dto.bootstrap_paths_dto import BootstrapPathsDTO
|
|
7
7
|
from plexutil.exception.auth_error import AuthError
|
|
@@ -13,9 +13,9 @@ from plexutil.util.icons import Icons
|
|
|
13
13
|
|
|
14
14
|
class Auth(Static):
|
|
15
15
|
@staticmethod
|
|
16
|
-
def
|
|
16
|
+
def get_account(
|
|
17
17
|
bootstrap_paths_dto: BootstrapPathsDTO,
|
|
18
|
-
) ->
|
|
18
|
+
) -> MyPlexAccount:
|
|
19
19
|
"""
|
|
20
20
|
Login to Plex and returns a list of all the available Plex Resources
|
|
21
21
|
(Servers and Clients)
|
|
@@ -82,8 +82,4 @@ class Auth(Static):
|
|
|
82
82
|
description = "Auth exists"
|
|
83
83
|
PlexUtilLogger.get_logger().debug(description)
|
|
84
84
|
token, _ = FileImporter.get_jwt(bootstrap_paths_dto.token_dir)
|
|
85
|
-
|
|
86
|
-
resources = account.resources()
|
|
87
|
-
description = f"Available Resources: {resources}"
|
|
88
|
-
PlexUtilLogger.get_logger().debug(description)
|
|
89
|
-
return resources
|
|
85
|
+
return MyPlexAccount(token=token)
|
|
@@ -23,7 +23,7 @@ if TYPE_CHECKING:
|
|
|
23
23
|
MusicSection,
|
|
24
24
|
ShowSection,
|
|
25
25
|
)
|
|
26
|
-
from plexapi.myplex import
|
|
26
|
+
from plexapi.myplex import MyPlexAccount
|
|
27
27
|
from plexapi.server import PlexServer
|
|
28
28
|
from plexapi.video import Movie, Show
|
|
29
29
|
|
|
@@ -388,7 +388,7 @@ class Prompt(Static):
|
|
|
388
388
|
).value
|
|
389
389
|
|
|
390
390
|
@staticmethod
|
|
391
|
-
def confirm_server(
|
|
391
|
+
def confirm_server(plex_account: MyPlexAccount) -> PlexServer:
|
|
392
392
|
"""
|
|
393
393
|
Prompts user for a Plex Media Server selection
|
|
394
394
|
|
|
@@ -403,10 +403,17 @@ class Prompt(Static):
|
|
|
403
403
|
"""
|
|
404
404
|
is_default = True
|
|
405
405
|
dropdown = []
|
|
406
|
+
plex_resources = plex_account.resources()
|
|
407
|
+
description = f"Available Resources: {plex_resources}"
|
|
408
|
+
PlexUtilLogger.get_logger().debug(description)
|
|
409
|
+
|
|
410
|
+
pass_icon = f"{Icons.PASS} " if plex_account.subscriptionActive else ""
|
|
411
|
+
|
|
406
412
|
for resource in plex_resources:
|
|
413
|
+
display_name = f"{pass_icon}{resource.name} ({resource.device})"
|
|
407
414
|
if resource.product == "Plex Media Server":
|
|
408
415
|
item = DropdownItemDTO(
|
|
409
|
-
display_name=
|
|
416
|
+
display_name=display_name,
|
|
410
417
|
value=resource,
|
|
411
418
|
is_default=is_default,
|
|
412
419
|
)
|
|
@@ -423,6 +430,7 @@ class Prompt(Static):
|
|
|
423
430
|
try:
|
|
424
431
|
plex_server = plex_resource.connect()
|
|
425
432
|
except NotFound as e:
|
|
433
|
+
spinner.text = ""
|
|
426
434
|
spinner.fail(f"{Icons.FAILURE} Connection Failure")
|
|
427
435
|
description = (
|
|
428
436
|
f"Failed to connect to: {plex_resource.name} "
|
|
@@ -431,6 +439,7 @@ class Prompt(Static):
|
|
|
431
439
|
)
|
|
432
440
|
raise ServerConnectionError(description) from e
|
|
433
441
|
except Exception as e:
|
|
442
|
+
spinner.text = ""
|
|
434
443
|
spinner.fail(f"{Icons.FAILURE} Connection Failure")
|
|
435
444
|
description = (
|
|
436
445
|
f"Failed to connect to: {plex_resource.name} "
|
|
@@ -439,6 +448,7 @@ class Prompt(Static):
|
|
|
439
448
|
)
|
|
440
449
|
raise ServerConnectionError(description) from e
|
|
441
450
|
|
|
451
|
+
spinner.text = ""
|
|
442
452
|
spinner.ok(f"{Icons.SUCCESS} Connected")
|
|
443
453
|
|
|
444
454
|
description = f"Connected to: {plex_server}"
|
|
@@ -560,11 +570,11 @@ class Prompt(Static):
|
|
|
560
570
|
|
|
561
571
|
space = " " * offset
|
|
562
572
|
if dropdown_count < max_single_space:
|
|
563
|
-
number_format = f"[ {dropdown_count}]
|
|
573
|
+
number_format = f"[ {dropdown_count}]"
|
|
564
574
|
elif dropdown_count < max_double_space:
|
|
565
|
-
number_format = f"[ {dropdown_count}]
|
|
575
|
+
number_format = f"[ {dropdown_count}]"
|
|
566
576
|
else:
|
|
567
|
-
number_format = f"[{dropdown_count}]
|
|
577
|
+
number_format = f"[{dropdown_count}]"
|
|
568
578
|
|
|
569
579
|
if item.is_default and expect_input:
|
|
570
580
|
display_name = f"{item.display_name} {Icons.STAR}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plexutil-3.3.1 → plexutil-3.4.0}/src/plexutil/service/song_music_playlist_composite_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|