plexflow 0.0.140__py3-none-any.whl → 0.0.142__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.
@@ -18,6 +18,6 @@ def get_watchlist(**kwargs) -> MediaContainer:
18
18
  None
19
19
 
20
20
  """
21
- context = PlexAuthorizedRequestContext(base_url="https://metadata.provider.plex.tv")
21
+ context = PlexAuthorizedRequestContext(base_url="https://discover.provider.plex.tv")
22
22
  response = context.get(endpoint="/library/sections/watchlist/all", **kwargs)
23
23
  return from_json(response.content.decode("utf-8"))
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import argparse
5
+ import logging
6
+ import os
7
+ import shutil
8
+ import subprocess
9
+ import sys
10
+
11
+
12
+ # --- Custom Exceptions for Clearer Error Handling ---
13
+ class SubSyncError(Exception):
14
+ """Base exception for this tool."""
15
+ pass
16
+
17
+ class FFSubsyncExecutableError(SubSyncError):
18
+ """Raised when the ffsubsync executable is not found."""
19
+ pass
20
+
21
+ class FFSubsyncProcessError(SubSyncError):
22
+ """Raised when the ffsubsync process fails."""
23
+ def __init__(self, message, returncode, stdout, stderr):
24
+ super().__init__(message)
25
+ self.returncode = returncode
26
+ self.stdout = stdout
27
+ self.stderr = stderr
28
+
29
+ def synchronize_subtitle(
30
+ video_path: str,
31
+ subtitle_path: str,
32
+ output_path: str = None,
33
+ ffsubsync_path: str = 'ffsubsync'
34
+ ) -> str:
35
+ """
36
+ Synchronizes a subtitle file with a video using ffsubsync.
37
+
38
+ Args:
39
+ video_path: Path to the reference video file.
40
+ subtitle_path: Path to the subtitle file to synchronize.
41
+ output_path: Path for the synchronized output file. If None, a default
42
+ is generated next to the input subtitle.
43
+ ffsubsync_path: Path to the ffsubsync executable.
44
+
45
+ Returns:
46
+ The path to the successfully created synchronized subtitle file.
47
+
48
+ Raises:
49
+ FFSubsyncExecutableError: If ffsubsync or its dependencies are not found.
50
+ FileNotFoundError: If the input video or subtitle files do not exist.
51
+ FFSubsyncProcessError: If the ffsubsync process returns a non-zero exit code.
52
+ """
53
+ # 1. --- Pre-flight Checks ---
54
+ logging.info("Performing pre-flight checks...")
55
+ if not shutil.which(ffsubsync_path):
56
+ raise FFSubsyncExecutableError(
57
+ f"'{ffsubsync_path}' command not found. Please ensure ffsubsync is "
58
+ "installed (pip install ffsubsync) and in your system's PATH."
59
+ )
60
+
61
+ for fpath in [video_path, subtitle_path]:
62
+ if not os.path.exists(fpath):
63
+ raise FileNotFoundError(f"Input file not found at '{fpath}'")
64
+
65
+ # 2. --- Determine Output Path ---
66
+ if output_path is None:
67
+ base, ext = os.path.splitext(subtitle_path)
68
+ output_path = f"{base}_synced{ext}"
69
+
70
+ logging.info(f"Reference video: {video_path}")
71
+ logging.info(f"Input subtitle: {subtitle_path}")
72
+ logging.info(f"Output path: {output_path}")
73
+
74
+ # 3. --- Construct and Run the Command ---
75
+ command = [
76
+ ffsubsync_path,
77
+ video_path,
78
+ "-i", subtitle_path,
79
+ "-o", output_path,
80
+ ]
81
+ logging.debug(f"Executing command: {' '.join(command)}")
82
+
83
+ try:
84
+ result = subprocess.run(
85
+ command,
86
+ check=True, # Raises CalledProcessError on non-zero exit codes
87
+ capture_output=True,
88
+ text=True,
89
+ encoding='utf-8',
90
+ )
91
+ # ffsubsync logs to stderr, so we log it for debug purposes
92
+ logging.debug("ffsubsync process output (stderr):\n%s", result.stderr)
93
+
94
+ except subprocess.CalledProcessError as e:
95
+ raise FFSubsyncProcessError(
96
+ "ffsubsync failed during execution.",
97
+ returncode=e.returncode,
98
+ stdout=e.stdout,
99
+ stderr=e.stderr
100
+ ) from e
101
+
102
+ logging.info(f"Successfully synchronized subtitle to '{output_path}'")
103
+ return output_path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: plexflow
3
- Version: 0.0.140
3
+ Version: 0.0.142
4
4
  Summary: A short description of the package.
5
5
  License: MIT
6
6
  Keywords: keyword1,keyword2,keyword3
@@ -323,9 +323,9 @@ plexflow/core/plex/token/__pycache__/auto_token.cpython-312.pyc,sha256=1uRpJbyiW
323
323
  plexflow/core/plex/token/auto_token.py,sha256=CcAd6KcnI7ul5TxpdYVw_7T0ab2K3YTi8DcqHtjKt4Q,3615
324
324
  plexflow/core/plex/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
325
325
  plexflow/core/plex/utils/__pycache__/__init__.cpython-311.pyc,sha256=2b2qu_365BZcXqAU5s34hzrvKC0s2_W8OReMDlBr3Sc,174
326
- plexflow/core/plex/utils/__pycache__/__init__.cpython-312.pyc,sha256=c0Yk4iDt3y2vEr_P7Vp3CWPuAinLOeQq592IL-w1AiA,162
326
+ plexflow/core/plex/utils/__pycache__/__init__.cpython-312.pyc,sha256=kDTyAiv1LvPBl4_1L0O5-mL4S3Vxj12MsP0Cv8L2NC0,160
327
327
  plexflow/core/plex/utils/__pycache__/paginated.cpython-311.pyc,sha256=7WkEf0cLkNXyI5BHrAZndqSoR6NM-V0wW1Oi5uSIf0M,1523
328
- plexflow/core/plex/utils/__pycache__/paginated.cpython-312.pyc,sha256=vxpUDtw11STCsmwUC8tiqp_6FwVe3tn-Day_K5OPZHE,1385
328
+ plexflow/core/plex/utils/__pycache__/paginated.cpython-312.pyc,sha256=5dnkFug_9eFqj3zXm6CWPMw_N9tYwWy68F0mntRyWhM,1383
329
329
  plexflow/core/plex/utils/paginated.py,sha256=4w-Q2kpkCmsCYnxJazoltvvpLq-c2hzyS4DWsGHkeoM,1171
330
330
  plexflow/core/plex/watchlist/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
331
331
  plexflow/core/plex/watchlist/__pycache__/__init__.cpython-311.pyc,sha256=5GlwuWEZYpXuoiIJkYyX4h6wxwzMD9DUosgJ5Gw_6ZU,178
@@ -333,9 +333,9 @@ plexflow/core/plex/watchlist/__pycache__/__init__.cpython-312.pyc,sha256=FlojeaU
333
333
  plexflow/core/plex/watchlist/__pycache__/datatypes.cpython-311.pyc,sha256=raf3JEsEqRmBYH2FOfY4Wujcdmobp94rviGft5Z7jCQ,8849
334
334
  plexflow/core/plex/watchlist/__pycache__/datatypes.cpython-312.pyc,sha256=iOPW1Mhf5SuUFHMzATc2pqN_uF-_NAmcCrzeUReQEt0,7606
335
335
  plexflow/core/plex/watchlist/__pycache__/watchlist.cpython-311.pyc,sha256=CocErWnueQIN8ReWjjpteDvF7mDtsdlxvFe4TaMiKvY,1274
336
- plexflow/core/plex/watchlist/__pycache__/watchlist.cpython-312.pyc,sha256=zLFP394Wxxnb67jOZlUcFlh4KAelz_gyO-WbzcBTJHs,1294
336
+ plexflow/core/plex/watchlist/__pycache__/watchlist.cpython-312.pyc,sha256=hZpx1d7RgxUamD-kxd0qdcYs6EXwaS4Od53SUgG2FbU,1415
337
337
  plexflow/core/plex/watchlist/datatypes.py,sha256=Ukri8nM16-IKxPxia4n45syjtc401nMWSd3hgjdrJSE,5193
338
- plexflow/core/plex/watchlist/watchlist.py,sha256=3vtkxvjVWmVWLSRxptZoek0eeAX2tU0mQ-IsT6TBwB4,851
338
+ plexflow/core/plex/watchlist/watchlist.py,sha256=8WB_2zvf2xCc9IdOnUCjAIiFtCyCGK2hU4ORu72Lzjw,851
339
339
  plexflow/core/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
340
340
  plexflow/core/storage/__pycache__/__init__.cpython-311.pyc,sha256=kKE5c5UA7CgoFly4hrI7a7s-ztUxg3zLnkjgpShAj2k,171
341
341
  plexflow/core/storage/__pycache__/__init__.cpython-312.pyc,sha256=bkMvtPZ53O_tyElEvOeGWcjGR-DEufOi4f0zHQeJFXo,157
@@ -725,9 +725,9 @@ plexflow/utils/torrent/extract/torrentquest.py,sha256=gQn9GanFM5SXvpwjcyRu0XgTZ2
725
725
  plexflow/utils/torrent/files.py,sha256=XJxvFedZQb8H-wSzNIZI_2nUOT-pqr6MwgYcoty0yA0,2285
726
726
  plexflow/utils/torrent/hash.py,sha256=yaVAXj6t4qouNVUdZ-ulgrhTSLsp7DOggyB6sanCPX8,3162
727
727
  plexflow/utils/transcribe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
728
- plexflow/utils/transcribe/__pycache__/__init__.cpython-312.pyc,sha256=uz1p6LU0YlLilrO5jq7FocDsrHhLldFGpTAFwicVPlU,163
728
+ plexflow/utils/transcribe/__pycache__/__init__.cpython-312.pyc,sha256=AEEtGtOBmfH0I2QiG4MzzInGJracQnS7YyNLJ5Gwg2s,161
729
729
  plexflow/utils/transcribe/__pycache__/speech2text.cpython-311.pyc,sha256=WcYPF8JcosrCCwmIFl0eamZpasICUBJ_MeUS_Ok7zUs,1632
730
- plexflow/utils/transcribe/__pycache__/speech2text.cpython-312.pyc,sha256=dY538EbFsJXzZr3139_TrtuLytcmculX_yBhi9DeKaM,2842
730
+ plexflow/utils/transcribe/__pycache__/speech2text.cpython-312.pyc,sha256=DqZEkcJR1rubjolqlFp6Y-Ed2lh-MTSoHMUS4N_6sRA,2822
731
731
  plexflow/utils/transcribe/speech2text.py,sha256=ldcZqx18Yr8aa-y5sw7WaEKCci9mvBI0z06YQqJemnU,3547
732
732
  plexflow/utils/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
733
733
  plexflow/utils/video/__pycache__/__init__.cpython-312.pyc,sha256=SA7I28R8t-m5Q4uA7laJCUz3JHqVgUtkvewvrAk1qVk,156
@@ -735,7 +735,8 @@ plexflow/utils/video/__pycache__/audio.cpython-312.pyc,sha256=kmzGDCHSC1hWyHwRut
735
735
  plexflow/utils/video/__pycache__/subtitle.cpython-312.pyc,sha256=PCjpCLydGXaRsQy6cikhgsEs8WlComfOoYPiLFqfVMA,2515
736
736
  plexflow/utils/video/audio.py,sha256=Pd8OuQHX2QN-lc5iYkB0Vo1OEHmTcvDYH-uKud1f1q4,5262
737
737
  plexflow/utils/video/subtitle.py,sha256=qPvvBjlPj0fynJJvGJgGeKt9ey26R-cF6EoLaYt9iXU,1333
738
- plexflow-0.0.140.dist-info/METADATA,sha256=27yq2pNtHNgLWCkYfnzdGNgCnHd_Abzl_oMDJ7c-nmo,2971
739
- plexflow-0.0.140.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
740
- plexflow-0.0.140.dist-info/entry_points.txt,sha256=9RJC3ikOQORHNOn573EdwJOBUnFU_4EGHbtNUM5pjjY,1557
741
- plexflow-0.0.140.dist-info/RECORD,,
738
+ plexflow/utils/video/sync.py,sha256=LqBA0M-9MIozYNtZA4BzQfNjl8uWoV7doxhzKC6mlxU,3347
739
+ plexflow-0.0.142.dist-info/METADATA,sha256=UKKl8iO9rQVAgo2QogikQJOMV-llDRXmtzX7ES3qahI,2971
740
+ plexflow-0.0.142.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
741
+ plexflow-0.0.142.dist-info/entry_points.txt,sha256=9RJC3ikOQORHNOn573EdwJOBUnFU_4EGHbtNUM5pjjY,1557
742
+ plexflow-0.0.142.dist-info/RECORD,,