lightning-pose-app 1.8.1a2__py3-none-any.whl → 1.8.1a3__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.
- {lightning_pose_app-1.8.1a2.dist-info → lightning_pose_app-1.8.1a3.dist-info}/METADATA +1 -1
- lightning_pose_app-1.8.1a3.dist-info/RECORD +21 -0
- litpose_app/main.py +300 -300
- litpose_app/ngdist/ng_app/index.html +2 -2
- litpose_app/ngdist/ng_app/{main-WFYIUX2C.js → main-LJHMLKBL.js} +199 -149
- litpose_app/ngdist/ng_app/main-LJHMLKBL.js.map +1 -0
- litpose_app/ngdist/ng_app/{styles-AJ6NQDUD.css → styles-4V6RXJMC.css} +27 -7
- litpose_app/ngdist/ng_app/{styles-AJ6NQDUD.css.map → styles-4V6RXJMC.css.map} +2 -2
- litpose_app/ngdist/ng_app/video-tile.component-XSYKMARQ.css.map +7 -0
- litpose_app/run_ffprobe.py +132 -132
- litpose_app/super_rglob.py +48 -48
- lightning_pose_app-1.8.1a2.dist-info/RECORD +0 -20
- litpose_app/ngdist/ng_app/main-WFYIUX2C.js.map +0 -1
- {lightning_pose_app-1.8.1a2.dist-info → lightning_pose_app-1.8.1a3.dist-info}/WHEEL +0 -0
- /litpose_app/ngdist/ng_app/{app.component-IZ5OUDH2.css.map → app.component-UHVEDPZR.css.map} +0 -0
- /litpose_app/ngdist/ng_app/{project-settings.component-BXKZMYM3.css.map → project-settings.component-5IRK7U7U.css.map} +0 -0
- /litpose_app/ngdist/ng_app/{viewer-page.component-KIYG73MW.css.map → viewer-page.component-MRTIUFL2.css.map} +0 -0
litpose_app/run_ffprobe.py
CHANGED
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
import json
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def run_ffprobe(video_path):
|
|
7
|
-
"""
|
|
8
|
-
Executes ffprobe to get video metadata and parses the JSON output.
|
|
9
|
-
|
|
10
|
-
Args:
|
|
11
|
-
video_path (str): The path to the video file.
|
|
12
|
-
|
|
13
|
-
Returns:
|
|
14
|
-
dict: A dictionary containing the parsed metadata, or None if an error occurs.
|
|
15
|
-
"""
|
|
16
|
-
command = [
|
|
17
|
-
"ffprobe",
|
|
18
|
-
"-v",
|
|
19
|
-
"error", # Suppress verbose output
|
|
20
|
-
"-select_streams",
|
|
21
|
-
"v:0", # Select the first video stream
|
|
22
|
-
"-show_entries",
|
|
23
|
-
"format=duration:stream=avg_frame_rate,codec_name,width,height,display_aspect_ratio",
|
|
24
|
-
"-of",
|
|
25
|
-
"json", # Output in JSON format
|
|
26
|
-
video_path,
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
# Initialize extracted_info with default/None values and an error key
|
|
30
|
-
extracted_info = {
|
|
31
|
-
"codec": None,
|
|
32
|
-
"width": None,
|
|
33
|
-
"height": None,
|
|
34
|
-
"fps": None,
|
|
35
|
-
"duration": None,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
try:
|
|
39
|
-
# Execute the ffprobe command
|
|
40
|
-
process = subprocess.run(command, capture_output=True, text=True, check=True)
|
|
41
|
-
|
|
42
|
-
# Parse the JSON output
|
|
43
|
-
metadata = json.loads(process.stdout)
|
|
44
|
-
|
|
45
|
-
# --- Extracting Data ---
|
|
46
|
-
if "format" in metadata and "duration" in metadata["format"]:
|
|
47
|
-
try:
|
|
48
|
-
extracted_info["duration"] = float(metadata["format"]["duration"])
|
|
49
|
-
except ValueError:
|
|
50
|
-
extracted_info["error"] = (
|
|
51
|
-
f"Failed to parse duration: {metadata['format']['duration']}"
|
|
52
|
-
)
|
|
53
|
-
return extracted_info
|
|
54
|
-
|
|
55
|
-
if "streams" in metadata and len(metadata["streams"]) > 0:
|
|
56
|
-
video_stream = metadata["streams"][
|
|
57
|
-
0
|
|
58
|
-
] # Assuming we want the first video stream
|
|
59
|
-
|
|
60
|
-
# Codec
|
|
61
|
-
if "codec_name" in video_stream:
|
|
62
|
-
extracted_info["codec"] = str(video_stream["codec_name"])
|
|
63
|
-
|
|
64
|
-
# Width and Height
|
|
65
|
-
if "width" in video_stream:
|
|
66
|
-
try:
|
|
67
|
-
extracted_info["width"] = int(video_stream["width"])
|
|
68
|
-
except ValueError:
|
|
69
|
-
extracted_info["error"] = (
|
|
70
|
-
f"Failed to parse width: {video_stream['width']}"
|
|
71
|
-
)
|
|
72
|
-
return extracted_info
|
|
73
|
-
if "height" in video_stream:
|
|
74
|
-
try:
|
|
75
|
-
extracted_info["height"] = int(video_stream["height"])
|
|
76
|
-
except ValueError:
|
|
77
|
-
extracted_info["error"] = (
|
|
78
|
-
f"Failed to parse height: {video_stream['height']}"
|
|
79
|
-
)
|
|
80
|
-
return extracted_info
|
|
81
|
-
|
|
82
|
-
# FPS
|
|
83
|
-
if "avg_frame_rate" in video_stream:
|
|
84
|
-
rate_str = video_stream["avg_frame_rate"]
|
|
85
|
-
if "/" in rate_str:
|
|
86
|
-
try:
|
|
87
|
-
num, den = map(int, rate_str.split("/"))
|
|
88
|
-
if den != 0: # Avoid division by zero
|
|
89
|
-
extracted_info["fps"] = round(num / den)
|
|
90
|
-
else:
|
|
91
|
-
extracted_info["error"] = (
|
|
92
|
-
f"Framerate denominator is zero: {rate_str}"
|
|
93
|
-
)
|
|
94
|
-
return extracted_info
|
|
95
|
-
except ValueError:
|
|
96
|
-
extracted_info["error"] = (
|
|
97
|
-
f"Failed to parse fractional framerate: {rate_str}"
|
|
98
|
-
)
|
|
99
|
-
return extracted_info
|
|
100
|
-
else:
|
|
101
|
-
try:
|
|
102
|
-
extracted_info["fps"] = round(float(rate_str))
|
|
103
|
-
except ValueError:
|
|
104
|
-
extracted_info["error"] = (
|
|
105
|
-
f"Failed to parse float framerate: {rate_str}"
|
|
106
|
-
)
|
|
107
|
-
return extracted_info
|
|
108
|
-
|
|
109
|
-
return extracted_info
|
|
110
|
-
|
|
111
|
-
except FileNotFoundError:
|
|
112
|
-
extracted_info["error"] = (
|
|
113
|
-
"ffprobe command not found. Please ensure FFmpeg (which includes ffprobe) is installed and accessible in your system's PATH."
|
|
114
|
-
)
|
|
115
|
-
return extracted_info
|
|
116
|
-
except subprocess.CalledProcessError as e:
|
|
117
|
-
extracted_info["error"] = (
|
|
118
|
-
f"ffprobe command failed with exit code {e.returncode}. "
|
|
119
|
-
f"Command: {' '.join(command)}. "
|
|
120
|
-
f"Stdout: {e.stdout.strip()}. "
|
|
121
|
-
f"Stderr: {e.stderr.strip()}"
|
|
122
|
-
)
|
|
123
|
-
return extracted_info
|
|
124
|
-
except json.JSONDecodeError as e:
|
|
125
|
-
extracted_info["error"] = (
|
|
126
|
-
f"Failed to parse JSON output from ffprobe. Error details: {e}. "
|
|
127
|
-
f"ffprobe stdout (attempted JSON): {process.stdout.strip()}"
|
|
128
|
-
)
|
|
129
|
-
return extracted_info
|
|
130
|
-
except Exception as e:
|
|
131
|
-
extracted_info["error"] = f"An unexpected error occurred: {e}"
|
|
132
|
-
return extracted_info
|
|
1
|
+
import subprocess
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def run_ffprobe(video_path):
|
|
7
|
+
"""
|
|
8
|
+
Executes ffprobe to get video metadata and parses the JSON output.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
video_path (str): The path to the video file.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
dict: A dictionary containing the parsed metadata, or None if an error occurs.
|
|
15
|
+
"""
|
|
16
|
+
command = [
|
|
17
|
+
"ffprobe",
|
|
18
|
+
"-v",
|
|
19
|
+
"error", # Suppress verbose output
|
|
20
|
+
"-select_streams",
|
|
21
|
+
"v:0", # Select the first video stream
|
|
22
|
+
"-show_entries",
|
|
23
|
+
"format=duration:stream=avg_frame_rate,codec_name,width,height,display_aspect_ratio",
|
|
24
|
+
"-of",
|
|
25
|
+
"json", # Output in JSON format
|
|
26
|
+
video_path,
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# Initialize extracted_info with default/None values and an error key
|
|
30
|
+
extracted_info = {
|
|
31
|
+
"codec": None,
|
|
32
|
+
"width": None,
|
|
33
|
+
"height": None,
|
|
34
|
+
"fps": None,
|
|
35
|
+
"duration": None,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
# Execute the ffprobe command
|
|
40
|
+
process = subprocess.run(command, capture_output=True, text=True, check=True)
|
|
41
|
+
|
|
42
|
+
# Parse the JSON output
|
|
43
|
+
metadata = json.loads(process.stdout)
|
|
44
|
+
|
|
45
|
+
# --- Extracting Data ---
|
|
46
|
+
if "format" in metadata and "duration" in metadata["format"]:
|
|
47
|
+
try:
|
|
48
|
+
extracted_info["duration"] = float(metadata["format"]["duration"])
|
|
49
|
+
except ValueError:
|
|
50
|
+
extracted_info["error"] = (
|
|
51
|
+
f"Failed to parse duration: {metadata['format']['duration']}"
|
|
52
|
+
)
|
|
53
|
+
return extracted_info
|
|
54
|
+
|
|
55
|
+
if "streams" in metadata and len(metadata["streams"]) > 0:
|
|
56
|
+
video_stream = metadata["streams"][
|
|
57
|
+
0
|
|
58
|
+
] # Assuming we want the first video stream
|
|
59
|
+
|
|
60
|
+
# Codec
|
|
61
|
+
if "codec_name" in video_stream:
|
|
62
|
+
extracted_info["codec"] = str(video_stream["codec_name"])
|
|
63
|
+
|
|
64
|
+
# Width and Height
|
|
65
|
+
if "width" in video_stream:
|
|
66
|
+
try:
|
|
67
|
+
extracted_info["width"] = int(video_stream["width"])
|
|
68
|
+
except ValueError:
|
|
69
|
+
extracted_info["error"] = (
|
|
70
|
+
f"Failed to parse width: {video_stream['width']}"
|
|
71
|
+
)
|
|
72
|
+
return extracted_info
|
|
73
|
+
if "height" in video_stream:
|
|
74
|
+
try:
|
|
75
|
+
extracted_info["height"] = int(video_stream["height"])
|
|
76
|
+
except ValueError:
|
|
77
|
+
extracted_info["error"] = (
|
|
78
|
+
f"Failed to parse height: {video_stream['height']}"
|
|
79
|
+
)
|
|
80
|
+
return extracted_info
|
|
81
|
+
|
|
82
|
+
# FPS
|
|
83
|
+
if "avg_frame_rate" in video_stream:
|
|
84
|
+
rate_str = video_stream["avg_frame_rate"]
|
|
85
|
+
if "/" in rate_str:
|
|
86
|
+
try:
|
|
87
|
+
num, den = map(int, rate_str.split("/"))
|
|
88
|
+
if den != 0: # Avoid division by zero
|
|
89
|
+
extracted_info["fps"] = round(num / den)
|
|
90
|
+
else:
|
|
91
|
+
extracted_info["error"] = (
|
|
92
|
+
f"Framerate denominator is zero: {rate_str}"
|
|
93
|
+
)
|
|
94
|
+
return extracted_info
|
|
95
|
+
except ValueError:
|
|
96
|
+
extracted_info["error"] = (
|
|
97
|
+
f"Failed to parse fractional framerate: {rate_str}"
|
|
98
|
+
)
|
|
99
|
+
return extracted_info
|
|
100
|
+
else:
|
|
101
|
+
try:
|
|
102
|
+
extracted_info["fps"] = round(float(rate_str))
|
|
103
|
+
except ValueError:
|
|
104
|
+
extracted_info["error"] = (
|
|
105
|
+
f"Failed to parse float framerate: {rate_str}"
|
|
106
|
+
)
|
|
107
|
+
return extracted_info
|
|
108
|
+
|
|
109
|
+
return extracted_info
|
|
110
|
+
|
|
111
|
+
except FileNotFoundError:
|
|
112
|
+
extracted_info["error"] = (
|
|
113
|
+
"ffprobe command not found. Please ensure FFmpeg (which includes ffprobe) is installed and accessible in your system's PATH."
|
|
114
|
+
)
|
|
115
|
+
return extracted_info
|
|
116
|
+
except subprocess.CalledProcessError as e:
|
|
117
|
+
extracted_info["error"] = (
|
|
118
|
+
f"ffprobe command failed with exit code {e.returncode}. "
|
|
119
|
+
f"Command: {' '.join(command)}. "
|
|
120
|
+
f"Stdout: {e.stdout.strip()}. "
|
|
121
|
+
f"Stderr: {e.stderr.strip()}"
|
|
122
|
+
)
|
|
123
|
+
return extracted_info
|
|
124
|
+
except json.JSONDecodeError as e:
|
|
125
|
+
extracted_info["error"] = (
|
|
126
|
+
f"Failed to parse JSON output from ffprobe. Error details: {e}. "
|
|
127
|
+
f"ffprobe stdout (attempted JSON): {process.stdout.strip()}"
|
|
128
|
+
)
|
|
129
|
+
return extracted_info
|
|
130
|
+
except Exception as e:
|
|
131
|
+
extracted_info["error"] = f"An unexpected error occurred: {e}"
|
|
132
|
+
return extracted_info
|
litpose_app/super_rglob.py
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
|
|
3
|
-
from wcmatch import pathlib as w
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def super_rglob(base_path, pattern=None, no_dirs=False, stat=False):
|
|
7
|
-
"""
|
|
8
|
-
Needs to be performant when searching over large model directory.
|
|
9
|
-
Uses wcmatch to exclude directories with extra calls to Path.is_dir.
|
|
10
|
-
wcmatch includes features that may be helpful down the line.
|
|
11
|
-
"""
|
|
12
|
-
if pattern is None:
|
|
13
|
-
pattern = "**/*"
|
|
14
|
-
flags = w.GLOBSTAR
|
|
15
|
-
if no_dirs:
|
|
16
|
-
flags |= w.NODIR
|
|
17
|
-
results = w.Path(base_path).glob(
|
|
18
|
-
pattern,
|
|
19
|
-
flags=flags,
|
|
20
|
-
)
|
|
21
|
-
result_dicts = []
|
|
22
|
-
for r in results:
|
|
23
|
-
stat_info = r.stat() if stat else None
|
|
24
|
-
is_dir = False if no_dirs else r.is_dir() if stat else None
|
|
25
|
-
if no_dirs and is_dir:
|
|
26
|
-
continue
|
|
27
|
-
entry_relative_path = r.relative_to(base_path)
|
|
28
|
-
d = {
|
|
29
|
-
"path": entry_relative_path,
|
|
30
|
-
"type": "dir" if is_dir else "file" if is_dir == False else None,
|
|
31
|
-
"size": stat_info.st_size if stat_info else None,
|
|
32
|
-
# Note: st_birthtime is more reliable for creation time on some systems
|
|
33
|
-
"cTime": (
|
|
34
|
-
datetime.datetime.fromtimestamp(
|
|
35
|
-
getattr(stat_info, "st_birthtime", stat_info.st_ctime)
|
|
36
|
-
).isoformat()
|
|
37
|
-
if stat_info
|
|
38
|
-
else None
|
|
39
|
-
),
|
|
40
|
-
"mTime": (
|
|
41
|
-
datetime.datetime.fromtimestamp(stat_info.st_mtime).isoformat()
|
|
42
|
-
if stat_info
|
|
43
|
-
else None
|
|
44
|
-
),
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
result_dicts.append(d)
|
|
48
|
-
return result_dicts
|
|
1
|
+
import datetime
|
|
2
|
+
|
|
3
|
+
from wcmatch import pathlib as w
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def super_rglob(base_path, pattern=None, no_dirs=False, stat=False):
|
|
7
|
+
"""
|
|
8
|
+
Needs to be performant when searching over large model directory.
|
|
9
|
+
Uses wcmatch to exclude directories with extra calls to Path.is_dir.
|
|
10
|
+
wcmatch includes features that may be helpful down the line.
|
|
11
|
+
"""
|
|
12
|
+
if pattern is None:
|
|
13
|
+
pattern = "**/*"
|
|
14
|
+
flags = w.GLOBSTAR
|
|
15
|
+
if no_dirs:
|
|
16
|
+
flags |= w.NODIR
|
|
17
|
+
results = w.Path(base_path).glob(
|
|
18
|
+
pattern,
|
|
19
|
+
flags=flags,
|
|
20
|
+
)
|
|
21
|
+
result_dicts = []
|
|
22
|
+
for r in results:
|
|
23
|
+
stat_info = r.stat() if stat else None
|
|
24
|
+
is_dir = False if no_dirs else r.is_dir() if stat else None
|
|
25
|
+
if no_dirs and is_dir:
|
|
26
|
+
continue
|
|
27
|
+
entry_relative_path = r.relative_to(base_path)
|
|
28
|
+
d = {
|
|
29
|
+
"path": entry_relative_path,
|
|
30
|
+
"type": "dir" if is_dir else "file" if is_dir == False else None,
|
|
31
|
+
"size": stat_info.st_size if stat_info else None,
|
|
32
|
+
# Note: st_birthtime is more reliable for creation time on some systems
|
|
33
|
+
"cTime": (
|
|
34
|
+
datetime.datetime.fromtimestamp(
|
|
35
|
+
getattr(stat_info, "st_birthtime", stat_info.st_ctime)
|
|
36
|
+
).isoformat()
|
|
37
|
+
if stat_info
|
|
38
|
+
else None
|
|
39
|
+
),
|
|
40
|
+
"mTime": (
|
|
41
|
+
datetime.datetime.fromtimestamp(stat_info.st_mtime).isoformat()
|
|
42
|
+
if stat_info
|
|
43
|
+
else None
|
|
44
|
+
),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
result_dicts.append(d)
|
|
48
|
+
return result_dicts
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
litpose_app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
litpose_app/main.py,sha256=UQ9WIxjHDDckhcjSwFqiuKj84tO7Ohvf6tP_OiiMIpE,9737
|
|
3
|
-
litpose_app/ngdist/ng_app/3rdpartylicenses.txt,sha256=k34Q8jZikvFWsgFXPlQxFJVcqMXDEiKKzC_VIEK8jNs,25366
|
|
4
|
-
litpose_app/ngdist/ng_app/app.component-IZ5OUDH2.css.map,sha256=e6lXWzmK3xppKK3tXHUccK1yGZqd1kzyTpDH0F1nC2g,344
|
|
5
|
-
litpose_app/ngdist/ng_app/error-dialog.component-HYLQSJEP.css.map,sha256=zJuF-LfB994Y1IrnIz38mariDFb8yucffbWPXgHGbvw,355
|
|
6
|
-
litpose_app/ngdist/ng_app/favicon.ico,sha256=QtbXVfx3HI-WqWh_kkBIQyYzJsDmLw_3Y4_UN7pBepE,15406
|
|
7
|
-
litpose_app/ngdist/ng_app/index.html,sha256=FA0fsUwQVubXOgASPFXVR4cHlWgcKXezeXR4QX5wYdg,22954
|
|
8
|
-
litpose_app/ngdist/ng_app/main-WFYIUX2C.js,sha256=ZzmVXvxTaXNe0akOR1LXkJNTF9cPinKAUc5MNEM0MMY,2719071
|
|
9
|
-
litpose_app/ngdist/ng_app/main-WFYIUX2C.js.map,sha256=iN_kYNo-dAPFZSLWZ-EFFkKYhOnTTpYfSMOMPQ9PF3g,5553036
|
|
10
|
-
litpose_app/ngdist/ng_app/prerendered-routes.json,sha256=p53cyKEVGQ6cGUee02kUdBp9HbdPChFTUp78gHJVBf4,18
|
|
11
|
-
litpose_app/ngdist/ng_app/project-settings.component-BXKZMYM3.css.map,sha256=v5tyba9p8ec3ZbHYyyUGTEFdEAsqT0l7JqtGRGjki6w,371
|
|
12
|
-
litpose_app/ngdist/ng_app/styles-AJ6NQDUD.css,sha256=IFn3SaSSlwBudgsGOQj_GirVrrJ0moGfEYouc9FLj6g,68857
|
|
13
|
-
litpose_app/ngdist/ng_app/styles-AJ6NQDUD.css.map,sha256=hC5GJkT1Xw6TZqjnb9c5tCUOW17HNwqirjMpJaLKw50,74649
|
|
14
|
-
litpose_app/ngdist/ng_app/video-player-controls.component-C4JZHYJ2.css.map,sha256=vX-dgeDCUCPLiea4Qy9O_EBm6IzzwB7R_uSBa0qU5Go,771
|
|
15
|
-
litpose_app/ngdist/ng_app/viewer-page.component-KIYG73MW.css.map,sha256=Uf1FgoCiF_qJpD4Ggk34Dq7kM73Q7i7NT6h3m30tbaY,211
|
|
16
|
-
litpose_app/run_ffprobe.py,sha256=VlZhCzaqqn7xy7Opb3GrBsWdWX_q_5JoF7n_Dg5l3Fc,4843
|
|
17
|
-
litpose_app/super_rglob.py,sha256=uk5u2WKQ10L4sWvQ0aTxHiKD-yXRnwxbwAg9ci3JlYI,1571
|
|
18
|
-
lightning_pose_app-1.8.1a2.dist-info/METADATA,sha256=zVkJb7nbH8IAHWf8BbYn8sUYnLXG1RfGohk7DqBLgNQ,473
|
|
19
|
-
lightning_pose_app-1.8.1a2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
20
|
-
lightning_pose_app-1.8.1a2.dist-info/RECORD,,
|