VideoTubeEditor 1.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.
- VideoTubeEditor/__init__.py +8 -0
- VideoTubeEditor/__main__.py +6 -0
- VideoTubeEditor/about_page.py +280 -0
- VideoTubeEditor/check_system.py +521 -0
- VideoTubeEditor/cli.py +720 -0
- VideoTubeEditor/edit_walk.py +470 -0
- VideoTubeEditor/encoder.py +456 -0
- VideoTubeEditor/file_stage.py +74 -0
- VideoTubeEditor/gui.py +1992 -0
- VideoTubeEditor/host_setup.py +224 -0
- VideoTubeEditor/join.py +355 -0
- VideoTubeEditor/media_info.py +68 -0
- VideoTubeEditor/menu_language.py +1669 -0
- VideoTubeEditor/menu_model.py +273 -0
- VideoTubeEditor/menu_painter.py +462 -0
- VideoTubeEditor/menu_session.py +118 -0
- VideoTubeEditor/run_output.py +114 -0
- VideoTubeEditor/self_management.py +79 -0
- VideoTubeEditor/system_log.py +92 -0
- VideoTubeEditor/tui.py +728 -0
- videotubeeditor-1.0.1.dist-info/METADATA +328 -0
- videotubeeditor-1.0.1.dist-info/RECORD +26 -0
- videotubeeditor-1.0.1.dist-info/WHEEL +5 -0
- videotubeeditor-1.0.1.dist-info/entry_points.txt +4 -0
- videotubeeditor-1.0.1.dist-info/licenses/LICENSE.md +21 -0
- videotubeeditor-1.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# About page composer.
|
|
3
|
+
# requirement-python-oop — class AboutPage.
|
|
4
|
+
# requirement-python-about — identity lines, host check, and the star box.
|
|
5
|
+
# requirement-domain-videoeditor — the domain sentence on the identity block.
|
|
6
|
+
# =============================================================================
|
|
7
|
+
from __future__ import print_function, unicode_literals
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from .check_system import CheckSystem
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AboutPage:
|
|
16
|
+
"""Identity lines, install sentence, and the star box. One class, one module.
|
|
17
|
+
|
|
18
|
+
The host check is CheckSystem. Cli writes CheckSystem(...) and passes it here.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
check,
|
|
24
|
+
app_name,
|
|
25
|
+
version,
|
|
26
|
+
author,
|
|
27
|
+
updated,
|
|
28
|
+
homepage,
|
|
29
|
+
download_url,
|
|
30
|
+
usage,
|
|
31
|
+
console_name,
|
|
32
|
+
logger=None,
|
|
33
|
+
):
|
|
34
|
+
self.logger = logger
|
|
35
|
+
if logger is not None:
|
|
36
|
+
logger.log_message("instantiated", component="AboutPage")
|
|
37
|
+
if not isinstance(check, CheckSystem):
|
|
38
|
+
raise TypeError("about host check is CheckSystem")
|
|
39
|
+
self.check = check
|
|
40
|
+
self.app_name = app_name
|
|
41
|
+
self.version = version
|
|
42
|
+
self.author = author
|
|
43
|
+
self.updated = updated
|
|
44
|
+
self.homepage = homepage
|
|
45
|
+
self.download_url = download_url
|
|
46
|
+
self.usage = usage
|
|
47
|
+
self.console_name = console_name
|
|
48
|
+
|
|
49
|
+
def _is_source_checkout(self, path):
|
|
50
|
+
"""True when path is this package inside a source tree that has pyproject.toml."""
|
|
51
|
+
marker = "{}src{}VideoTubeEditor{}".format(os.sep, os.sep, os.sep)
|
|
52
|
+
if marker not in path:
|
|
53
|
+
return False
|
|
54
|
+
cursor = os.path.dirname(path)
|
|
55
|
+
for _ in range(8):
|
|
56
|
+
if os.path.isfile(os.path.join(cursor, "pyproject.toml")):
|
|
57
|
+
return True
|
|
58
|
+
parent = os.path.dirname(cursor)
|
|
59
|
+
if parent == cursor:
|
|
60
|
+
return False
|
|
61
|
+
cursor = parent
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
def install_kind(self, path):
|
|
65
|
+
"""
|
|
66
|
+
General Purpose: global, local, or uninstalled for an about location.
|
|
67
|
+
A source checkout is uninstalled. A copy under the home directory is local.
|
|
68
|
+
"""
|
|
69
|
+
path = os.path.realpath(path)
|
|
70
|
+
parts = path.split(os.sep)
|
|
71
|
+
packaged = "site-packages" in parts or "dist-packages" in parts
|
|
72
|
+
if not packaged and self._is_source_checkout(path):
|
|
73
|
+
return "uninstalled"
|
|
74
|
+
home = os.path.realpath(os.path.expanduser("~"))
|
|
75
|
+
in_home = path == home or path.startswith(home + os.sep)
|
|
76
|
+
base = os.path.basename(path)
|
|
77
|
+
script_names = (
|
|
78
|
+
self.console_name,
|
|
79
|
+
self.app_name,
|
|
80
|
+
"video-tube-editor",
|
|
81
|
+
"video-join",
|
|
82
|
+
"video-speed",
|
|
83
|
+
)
|
|
84
|
+
if in_home and (packaged or base in script_names):
|
|
85
|
+
return "local"
|
|
86
|
+
if path.startswith("/usr/") or path.startswith("/opt/") or path.startswith("/bin/"):
|
|
87
|
+
return "global"
|
|
88
|
+
if packaged and not in_home:
|
|
89
|
+
return "global"
|
|
90
|
+
return "uninstalled"
|
|
91
|
+
|
|
92
|
+
def install_sentence(self, kind):
|
|
93
|
+
"""General Purpose: The location sentence inside the about box."""
|
|
94
|
+
if kind == "global":
|
|
95
|
+
return "You are using the GLOBAL INSTALLED version, location:"
|
|
96
|
+
if kind == "local":
|
|
97
|
+
return "You are using the LOCAL INSTALLED version, location:"
|
|
98
|
+
return "You are using an UNINSTALLED version, location:"
|
|
99
|
+
|
|
100
|
+
def about_box_lines(
|
|
101
|
+
self,
|
|
102
|
+
usage=None,
|
|
103
|
+
location=None,
|
|
104
|
+
kind=None,
|
|
105
|
+
homepage=None,
|
|
106
|
+
download_url=None,
|
|
107
|
+
author=None,
|
|
108
|
+
updated=None,
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
General Purpose: Star-bordered about box.
|
|
112
|
+
An empty download URL omits the install line.
|
|
113
|
+
The title uses the package version string. It is not a second integer triple.
|
|
114
|
+
"""
|
|
115
|
+
if usage is None:
|
|
116
|
+
usage = self.usage
|
|
117
|
+
if location is None:
|
|
118
|
+
location = self.check.self_location()
|
|
119
|
+
if kind is None:
|
|
120
|
+
kind = self.install_kind(location)
|
|
121
|
+
if homepage is None:
|
|
122
|
+
homepage = self.homepage
|
|
123
|
+
if download_url is None:
|
|
124
|
+
download_url = self.download_url
|
|
125
|
+
if author is None:
|
|
126
|
+
author = self.author
|
|
127
|
+
if updated is None:
|
|
128
|
+
updated = self.updated
|
|
129
|
+
app = self.install_sentence(kind)
|
|
130
|
+
python_exe = self.check.python_executable_name() or "python3"
|
|
131
|
+
msg1 = "{} ({}) by {} on {}".format(
|
|
132
|
+
self.app_name, self.version, author, updated
|
|
133
|
+
)
|
|
134
|
+
if download_url == "":
|
|
135
|
+
msg = [
|
|
136
|
+
msg1,
|
|
137
|
+
"",
|
|
138
|
+
app,
|
|
139
|
+
" {}".format(location),
|
|
140
|
+
"",
|
|
141
|
+
"Basic Usage:",
|
|
142
|
+
" {}".format(usage),
|
|
143
|
+
"",
|
|
144
|
+
"Please visit our homepage: ",
|
|
145
|
+
' "{}"'.format(homepage),
|
|
146
|
+
"",
|
|
147
|
+
"",
|
|
148
|
+
"",
|
|
149
|
+
"",
|
|
150
|
+
]
|
|
151
|
+
else:
|
|
152
|
+
msg = [
|
|
153
|
+
msg1,
|
|
154
|
+
"",
|
|
155
|
+
app,
|
|
156
|
+
" {}".format(location),
|
|
157
|
+
"",
|
|
158
|
+
"Basic Usage:",
|
|
159
|
+
" {}".format(usage),
|
|
160
|
+
"",
|
|
161
|
+
"Please visit our homepage: ",
|
|
162
|
+
' "{}"'.format(homepage),
|
|
163
|
+
"",
|
|
164
|
+
"Installation command:",
|
|
165
|
+
" curl -fsSL {} | {}".format(download_url, python_exe),
|
|
166
|
+
"",
|
|
167
|
+
]
|
|
168
|
+
if download_url == "":
|
|
169
|
+
if homepage == "":
|
|
170
|
+
max_line = len(msg) - 3
|
|
171
|
+
else:
|
|
172
|
+
max_line = len(msg) - 2
|
|
173
|
+
else:
|
|
174
|
+
max_line = len(msg) - 1
|
|
175
|
+
if max_line < 1:
|
|
176
|
+
max_line = len(msg)
|
|
177
|
+
max_len = 0
|
|
178
|
+
for index in range(0, max_line):
|
|
179
|
+
if len(msg[index]) > max_len:
|
|
180
|
+
max_len = len(msg[index])
|
|
181
|
+
boxed = []
|
|
182
|
+
for index in range(0, max_line):
|
|
183
|
+
boxed.append(msg[index] + (" " * (max_len - len(msg[index]))))
|
|
184
|
+
star = "*" * (max_len + 4)
|
|
185
|
+
blank = " " * max_len
|
|
186
|
+
lines = [star, "* {} *".format(blank)]
|
|
187
|
+
for row in boxed:
|
|
188
|
+
lines.append("* {} *".format(row))
|
|
189
|
+
lines.append("* {} *".format(blank))
|
|
190
|
+
lines.append(star)
|
|
191
|
+
return lines
|
|
192
|
+
|
|
193
|
+
def framework_about(self):
|
|
194
|
+
"""
|
|
195
|
+
General Purpose: About text for the menu result page.
|
|
196
|
+
requirement-python-about: identity (with window libraries), host check, and the install box.
|
|
197
|
+
"""
|
|
198
|
+
lines = [
|
|
199
|
+
"{} {}".format(self.app_name, self.version),
|
|
200
|
+
"Domain: Concatenate two local videos, and cut, speed, or boomerang an MP4",
|
|
201
|
+
"Runtime tools: FFmpeg (copy, re-encode, cut, speed); OpenCV (duration); GTK 4 and GStreamer (window)",
|
|
202
|
+
"Entry points: {}, video-join, video-speed, python -m {}".format(
|
|
203
|
+
self.console_name, self.app_name
|
|
204
|
+
),
|
|
205
|
+
]
|
|
206
|
+
lines.extend(self.window_library_lines())
|
|
207
|
+
lines.append("")
|
|
208
|
+
lines.extend(self.check.check_system_lines())
|
|
209
|
+
lines.append("")
|
|
210
|
+
lines.extend(self.about_box_lines())
|
|
211
|
+
return "\n".join(lines)
|
|
212
|
+
|
|
213
|
+
def _windows_host(self) -> bool:
|
|
214
|
+
"""True on Windows, including Windows Python under Git Bash.
|
|
215
|
+
|
|
216
|
+
requirement-python-windows. The miss text stays on requirement-python-about.
|
|
217
|
+
"""
|
|
218
|
+
if os.name == "nt" or sys.platform.startswith("win"):
|
|
219
|
+
return True
|
|
220
|
+
return os.environ.get("OS", "").lower().startswith("windows")
|
|
221
|
+
|
|
222
|
+
def _probe_window_libraries(self):
|
|
223
|
+
"""Read GTK 4 and GStreamer from this interpreter. Missing stays not available."""
|
|
224
|
+
gtk_text = "not available"
|
|
225
|
+
gst_text = "not available"
|
|
226
|
+
dist = "/usr/lib/python3/dist-packages"
|
|
227
|
+
if os.path.isdir(os.path.join(dist, "gi")) and dist not in sys.path:
|
|
228
|
+
sys.path.append(dist)
|
|
229
|
+
try:
|
|
230
|
+
import gi
|
|
231
|
+
|
|
232
|
+
gi.require_version("Gtk", "4.0")
|
|
233
|
+
from gi.repository import Gtk
|
|
234
|
+
|
|
235
|
+
gtk_text = "{}.{}.{}".format(
|
|
236
|
+
Gtk.get_major_version(),
|
|
237
|
+
Gtk.get_minor_version(),
|
|
238
|
+
Gtk.get_micro_version(),
|
|
239
|
+
)
|
|
240
|
+
except Exception:
|
|
241
|
+
gtk_text = "not available"
|
|
242
|
+
try:
|
|
243
|
+
import gi
|
|
244
|
+
|
|
245
|
+
gi.require_version("Gst", "1.0")
|
|
246
|
+
from gi.repository import Gst
|
|
247
|
+
|
|
248
|
+
major, minor, micro = Gst.version()[:3]
|
|
249
|
+
gst_text = "{}.{}.{}".format(major, minor, micro)
|
|
250
|
+
except Exception:
|
|
251
|
+
gst_text = "not available"
|
|
252
|
+
return gtk_text, gst_text
|
|
253
|
+
|
|
254
|
+
def window_library_lines(self, gtk_text=None, gst_text=None, on_windows=None):
|
|
255
|
+
"""GTK 4 and GStreamer for this Python. The lines stay text and install nothing."""
|
|
256
|
+
if gtk_text is None or gst_text is None:
|
|
257
|
+
found_gtk, found_gst = self._probe_window_libraries()
|
|
258
|
+
if gtk_text is None:
|
|
259
|
+
gtk_text = found_gtk
|
|
260
|
+
if gst_text is None:
|
|
261
|
+
gst_text = found_gst
|
|
262
|
+
if on_windows is None:
|
|
263
|
+
on_windows = self._windows_host()
|
|
264
|
+
lines = [
|
|
265
|
+
"Window libraries:",
|
|
266
|
+
" GTK 4: {}".format(gtk_text),
|
|
267
|
+
" GStreamer: {}".format(gst_text),
|
|
268
|
+
]
|
|
269
|
+
missing = gtk_text == "not available" or gst_text == "not available"
|
|
270
|
+
if on_windows and missing:
|
|
271
|
+
lines.extend(
|
|
272
|
+
[
|
|
273
|
+
" Windows: this Python cannot import GTK 4 and GStreamer.",
|
|
274
|
+
" The picture window needs both libraries in this Python. This page checks them and does not install them.",
|
|
275
|
+
" On Windows, run video-tube-editor tui.",
|
|
276
|
+
]
|
|
277
|
+
)
|
|
278
|
+
elif on_windows:
|
|
279
|
+
lines.append(" Windows: this Python can import GTK 4 and GStreamer.")
|
|
280
|
+
return lines
|