boris-behav-obs 9.3.5__py2.py3-none-any.whl → 9.4__py2.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.
- boris/1.py +45 -0
- boris/about.py +5 -4
- boris/config_file.py +1 -1
- boris/converters.py +1 -3
- boris/core.py +86 -65
- boris/dialog.py +4 -25
- boris/utilities.py +170 -75
- boris/version.py +2 -2
- {boris_behav_obs-9.3.5.dist-info → boris_behav_obs-9.4.dist-info}/METADATA +1 -1
- {boris_behav_obs-9.3.5.dist-info → boris_behav_obs-9.4.dist-info}/RECORD +14 -13
- {boris_behav_obs-9.3.5.dist-info → boris_behav_obs-9.4.dist-info}/WHEEL +1 -1
- {boris_behav_obs-9.3.5.dist-info → boris_behav_obs-9.4.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-9.3.5.dist-info → boris_behav_obs-9.4.dist-info}/licenses/LICENSE.TXT +0 -0
- {boris_behav_obs-9.3.5.dist-info → boris_behav_obs-9.4.dist-info}/top_level.txt +0 -0
boris/1.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
3
|
+
import mpv
|
|
4
|
+
|
|
5
|
+
player = mpv.MPV()
|
|
6
|
+
|
|
7
|
+
player.loop = True
|
|
8
|
+
player.play('/home/olivier/gdrive_sync/src/python/generate_video_test/video1.mp4')
|
|
9
|
+
player.wait_until_playing()
|
|
10
|
+
|
|
11
|
+
font = ImageFont.truetype('DejaVuSans.ttf', 40)
|
|
12
|
+
|
|
13
|
+
overlay = player.create_image_overlay()
|
|
14
|
+
|
|
15
|
+
img = Image.new('RGBA', (400, 150), (255, 255, 255, 0))
|
|
16
|
+
d = ImageDraw.Draw(img)
|
|
17
|
+
d.text((10, 10), 'Hello World', font=font, fill=(0, 255, 255, 128))
|
|
18
|
+
#d.text((10, 60), f't={ts:.3f}', font=font, fill=(255, 0, 255, 255))
|
|
19
|
+
|
|
20
|
+
pos = 100
|
|
21
|
+
|
|
22
|
+
overlay.update(img, pos=(2*pos, pos))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
while not player.core_idle:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
'''
|
|
30
|
+
for pos in range(0, 500, 5):
|
|
31
|
+
ts = player.time_pos
|
|
32
|
+
if ts is None:
|
|
33
|
+
break
|
|
34
|
+
|
|
35
|
+
img = Image.new('RGBA', (400, 150), (255, 255, 255, 0))
|
|
36
|
+
d = ImageDraw.Draw(img)
|
|
37
|
+
d.text((10, 10), 'Hello World', font=font, fill=(0, 255, 255, 128))
|
|
38
|
+
d.text((10, 60), f't={ts:.3f}', font=font, fill=(255, 0, 255, 255))
|
|
39
|
+
|
|
40
|
+
overlay.update(img, pos=(2*pos, pos))
|
|
41
|
+
time.sleep(0.05)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
overlay.remove()
|
|
45
|
+
'''
|
boris/about.py
CHANGED
|
@@ -31,7 +31,6 @@ from . import config as cfg
|
|
|
31
31
|
from . import utilities as util
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
from PySide6.QtCore import qVersion
|
|
35
34
|
from PySide6.QtGui import QPixmap
|
|
36
35
|
from PySide6.QtWidgets import QMessageBox
|
|
37
36
|
|
|
@@ -41,8 +40,6 @@ def actionAbout_activated(self):
|
|
|
41
40
|
About dialog
|
|
42
41
|
"""
|
|
43
42
|
|
|
44
|
-
import PySide6
|
|
45
|
-
|
|
46
43
|
programs_versions: list = ["MPV media player"]
|
|
47
44
|
|
|
48
45
|
mpv_lib_version, mpv_lib_file_path, mpv_api_version = util.mpv_lib_version()
|
|
@@ -108,6 +105,7 @@ def actionAbout_activated(self):
|
|
|
108
105
|
'<a href="https://besjournals.onlinelibrary.wiley.com/doi/full/10.1111/2041-210X.12584">DOI:10.1111/2041-210X.12584</a>'
|
|
109
106
|
)
|
|
110
107
|
)
|
|
108
|
+
"""
|
|
111
109
|
n = "\n"
|
|
112
110
|
current_system = platform.uname()
|
|
113
111
|
details = (
|
|
@@ -123,8 +121,11 @@ def actionAbout_activated(self):
|
|
|
123
121
|
f"Memory (RAM) Total: {memory.get('total_memory', 'Not available'):.2f} Mb "
|
|
124
122
|
f"Free: {memory.get('free_memory', 'Not available'):.2f} Mb\n\n"
|
|
125
123
|
)
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
details = util.get_systeminfo()
|
|
126
127
|
|
|
127
|
-
details += n.join(programs_versions)
|
|
128
|
+
details += "\n".join(programs_versions)
|
|
128
129
|
"""
|
|
129
130
|
memory_in_use = f"{utilities.rss_memory_used(self.pid)} Mb" if utilities.rss_memory_used(self.pid) != -1 else "Not available"
|
|
130
131
|
percent_memory_in_use = (f"({utilities.rss_memory_percent_used(self.pid):.1f} % of total memory)"
|
boris/config_file.py
CHANGED
boris/converters.py
CHANGED
|
@@ -22,8 +22,6 @@ This file is part of BORIS.
|
|
|
22
22
|
|
|
23
23
|
import sys
|
|
24
24
|
import json
|
|
25
|
-
import urllib.error
|
|
26
|
-
import urllib.parse
|
|
27
25
|
import urllib.request
|
|
28
26
|
|
|
29
27
|
|
|
@@ -314,7 +312,7 @@ def load_converters_from_file_repo(self, mode: str):
|
|
|
314
312
|
QMessageBox.critical(
|
|
315
313
|
self,
|
|
316
314
|
"BORIS",
|
|
317
|
-
(f"The code of {converter_name} converter produces an error:
|
|
315
|
+
(f"The code of {converter_name} converter produces an error: <br><b>{sys.exc_info()[1]}</b>"),
|
|
318
316
|
)
|
|
319
317
|
|
|
320
318
|
self.tw_converters.setRowCount(self.tw_converters.rowCount() + 1)
|
boris/core.py
CHANGED
|
@@ -19,34 +19,31 @@ This file is part of BORIS.
|
|
|
19
19
|
along with this program; if not see <http://www.gnu.org/licenses/>.
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
|
+
# ruff: noqa: E402
|
|
22
23
|
|
|
23
24
|
import os
|
|
24
25
|
import sys
|
|
26
|
+
import pathlib as pl
|
|
25
27
|
|
|
26
|
-
os.environ["PATH"] = os.path.dirname(__file__) + os.sep + "misc" + os.pathsep + os.environ["PATH"]
|
|
28
|
+
# os.environ["PATH"] = os.path.dirname(__file__) + os.sep + "misc" + os.pathsep + os.environ["PATH"]
|
|
27
29
|
|
|
30
|
+
os.environ["PATH"] = str(pl.Path(__file__).parent / "misc") + os.pathsep + os.environ["PATH"]
|
|
28
31
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".")))
|
|
29
32
|
|
|
30
|
-
|
|
31
33
|
import datetime
|
|
32
|
-
|
|
33
34
|
import json
|
|
34
35
|
import logging
|
|
35
|
-
import pathlib as pl
|
|
36
36
|
import platform
|
|
37
37
|
import re
|
|
38
38
|
import PIL.Image
|
|
39
39
|
import PIL.ImageEnhance
|
|
40
|
+
from PIL.ImageQt import Image
|
|
40
41
|
import subprocess
|
|
41
|
-
|
|
42
42
|
import locale
|
|
43
43
|
import tempfile
|
|
44
44
|
import time
|
|
45
|
-
import urllib.error
|
|
46
|
-
import urllib.parse
|
|
47
45
|
import urllib.request
|
|
48
46
|
from typing import Union, Tuple
|
|
49
|
-
|
|
50
47
|
from decimal import Decimal as dec
|
|
51
48
|
from decimal import ROUND_DOWN
|
|
52
49
|
import gzip
|
|
@@ -57,7 +54,6 @@ import shutil
|
|
|
57
54
|
|
|
58
55
|
matplotlib.use("QtAgg")
|
|
59
56
|
|
|
60
|
-
import PySide6
|
|
61
57
|
from PySide6.QtCore import (
|
|
62
58
|
Qt,
|
|
63
59
|
QPoint,
|
|
@@ -66,7 +62,6 @@ from PySide6.QtCore import (
|
|
|
66
62
|
QDateTime,
|
|
67
63
|
QUrl,
|
|
68
64
|
QAbstractTableModel,
|
|
69
|
-
qVersion,
|
|
70
65
|
QElapsedTimer,
|
|
71
66
|
QSettings,
|
|
72
67
|
)
|
|
@@ -88,7 +83,28 @@ from PySide6.QtWidgets import (
|
|
|
88
83
|
QStyledItemDelegate,
|
|
89
84
|
QTableWidgetItem,
|
|
90
85
|
)
|
|
91
|
-
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
from . import cmd_arguments
|
|
89
|
+
|
|
90
|
+
# parse command line arguments
|
|
91
|
+
(options, args) = cmd_arguments.parse_arguments()
|
|
92
|
+
|
|
93
|
+
# set logging parameters
|
|
94
|
+
if options.debug:
|
|
95
|
+
logging.basicConfig(
|
|
96
|
+
format="%(asctime)s,%(msecs)d %(module)s l.%(lineno)d %(levelname)s %(message)s",
|
|
97
|
+
datefmt="%H:%M:%S",
|
|
98
|
+
level=logging.DEBUG,
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
logging.basicConfig(
|
|
102
|
+
format="%(asctime)s,%(msecs)d %(message)s",
|
|
103
|
+
datefmt="%H:%M:%S",
|
|
104
|
+
level=logging.INFO,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
from . import utilities as util
|
|
92
108
|
|
|
93
109
|
from . import dialog
|
|
94
110
|
from . import gui_utilities
|
|
@@ -105,21 +121,15 @@ from . import plot_waveform_rt
|
|
|
105
121
|
from . import plot_events_rt
|
|
106
122
|
from . import plugins
|
|
107
123
|
from . import project_functions
|
|
108
|
-
|
|
109
124
|
from . import select_observations
|
|
110
125
|
from . import subjects_pad
|
|
111
126
|
from . import version
|
|
112
127
|
from . import event_operations
|
|
113
|
-
from . import cmd_arguments
|
|
114
|
-
|
|
115
128
|
from . import core_qrc
|
|
116
129
|
from .core_ui import Ui_MainWindow
|
|
117
130
|
from . import config as cfg
|
|
118
131
|
from . import video_operations
|
|
119
|
-
|
|
120
132
|
from . import project
|
|
121
|
-
from . import utilities as util
|
|
122
|
-
|
|
123
133
|
from . import menu_options as menu_options
|
|
124
134
|
from . import connections as connections
|
|
125
135
|
from . import config_file
|
|
@@ -128,7 +138,7 @@ from . import observation_operations
|
|
|
128
138
|
from . import write_event
|
|
129
139
|
|
|
130
140
|
|
|
131
|
-
|
|
141
|
+
logging.debug("test")
|
|
132
142
|
|
|
133
143
|
__version__ = version.__version__
|
|
134
144
|
__version_date__ = version.__version_date__
|
|
@@ -143,44 +153,13 @@ if util.versiontuple(platform.python_version()) < util.versiontuple(MIN_PYTHON_V
|
|
|
143
153
|
if sys.platform == "darwin": # for MacOS
|
|
144
154
|
os.environ["LC_ALL"] = "en_US.UTF-8"
|
|
145
155
|
|
|
146
|
-
# parse command line arguments
|
|
147
|
-
(options, args) = cmd_arguments.parse_arguments()
|
|
148
|
-
|
|
149
|
-
# set logging parameters
|
|
150
|
-
if options.debug:
|
|
151
|
-
logging.basicConfig(
|
|
152
|
-
format="%(asctime)s,%(msecs)d %(module)s l.%(lineno)d %(levelname)s %(message)s",
|
|
153
|
-
datefmt="%H:%M:%S",
|
|
154
|
-
level=logging.DEBUG,
|
|
155
|
-
)
|
|
156
|
-
else:
|
|
157
|
-
logging.basicConfig(
|
|
158
|
-
format="%(asctime)s,%(msecs)d %(message)s",
|
|
159
|
-
datefmt="%H:%M:%S",
|
|
160
|
-
level=logging.INFO,
|
|
161
|
-
)
|
|
162
156
|
|
|
163
157
|
if options.version:
|
|
164
158
|
print(f"version {__version__} release date: {__version_date__}")
|
|
165
159
|
sys.exit(0)
|
|
166
160
|
|
|
167
|
-
|
|
168
161
|
logging.debug("BORIS started")
|
|
169
|
-
logging.info(
|
|
170
|
-
logging.info(f"Operating system: {platform.uname().system} {platform.uname().release} {platform.uname().version}")
|
|
171
|
-
logging.info(f"CPU: {platform.uname().machine} {platform.uname().processor}")
|
|
172
|
-
logging.info(f"Python {platform.python_version()} ({'64-bit' if sys.maxsize > 2**32 else '32-bit'})")
|
|
173
|
-
logging.info(f"Qt {qVersion()} - PySide {PySide6.__version__}")
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
(r, memory) = util.mem_info()
|
|
177
|
-
if not r:
|
|
178
|
-
logging.info(
|
|
179
|
-
(
|
|
180
|
-
f"Memory (RAM) Total: {memory.get('total_memory', 'Not available'):.2f} Mb "
|
|
181
|
-
f"Free: {memory.get('free_memory', 'Not available'):.2f} Mb"
|
|
182
|
-
)
|
|
183
|
-
)
|
|
162
|
+
logging.info(util.get_systeminfo())
|
|
184
163
|
|
|
185
164
|
|
|
186
165
|
def excepthook(exception_type, exception_value, traceback_object):
|
|
@@ -1362,7 +1341,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1362
1341
|
try:
|
|
1363
1342
|
last_version = urllib.request.urlopen(version_URL).read().strip().decode("utf-8")
|
|
1364
1343
|
except Exception:
|
|
1365
|
-
QMessageBox.warning(self, cfg.programName, "Can not check for updates
|
|
1344
|
+
QMessageBox.warning(self, cfg.programName, "Can not check for updates. Check your connection.")
|
|
1366
1345
|
return
|
|
1367
1346
|
|
|
1368
1347
|
# record check timestamp
|
|
@@ -5709,21 +5688,54 @@ def main():
|
|
|
5709
5688
|
|
|
5710
5689
|
locale.setlocale(locale.LC_NUMERIC, "C")
|
|
5711
5690
|
|
|
5712
|
-
# splashscreen
|
|
5713
|
-
# no splashscreen for Mac because it can mask the first use dialog box
|
|
5714
|
-
|
|
5715
|
-
if (not options.nosplashscreen) and (sys.platform != "darwin"):
|
|
5716
|
-
start = time.time()
|
|
5717
|
-
splash = QSplashScreen(QPixmap(":/splash"))
|
|
5718
|
-
splash.show()
|
|
5719
|
-
splash.raise_()
|
|
5720
|
-
app.processEvents()
|
|
5721
|
-
while time.time() - start < 1:
|
|
5722
|
-
time.sleep(0.001)
|
|
5723
|
-
|
|
5724
5691
|
# check FFmpeg
|
|
5725
5692
|
ret, msg = util.check_ffmpeg_path()
|
|
5726
5693
|
if not ret:
|
|
5694
|
+
if sys.platform.startswith("win"):
|
|
5695
|
+
QMessageBox.warning(
|
|
5696
|
+
None,
|
|
5697
|
+
cfg.programName,
|
|
5698
|
+
"FFmpeg is not available.<br>It will be downloaded",
|
|
5699
|
+
QMessageBox.Ok | QMessageBox.Default,
|
|
5700
|
+
QMessageBox.NoButton,
|
|
5701
|
+
)
|
|
5702
|
+
|
|
5703
|
+
# download ffmpeg and ffprobe from https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/
|
|
5704
|
+
url = "https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/"
|
|
5705
|
+
|
|
5706
|
+
# search where to download ffmpeg
|
|
5707
|
+
ffmpeg_dir = pl.Path(__file__).parent / "misc"
|
|
5708
|
+
|
|
5709
|
+
logging.debug(f"{ffmpeg_dir=}")
|
|
5710
|
+
|
|
5711
|
+
if not ffmpeg_dir.is_dir():
|
|
5712
|
+
logging.info(f"Creating {ffmpeg_dir} directory")
|
|
5713
|
+
ffmpeg_dir.mkdir(parents=True, exist_ok=True)
|
|
5714
|
+
|
|
5715
|
+
for file_ in ("ffmpeg.exe", "ffprobe.exe"):
|
|
5716
|
+
local_filename = ffmpeg_dir / file_
|
|
5717
|
+
logging.info(f"Downloading {file_}...")
|
|
5718
|
+
try:
|
|
5719
|
+
urllib.request.urlretrieve(url + file_, local_filename)
|
|
5720
|
+
except Exception:
|
|
5721
|
+
logging.critical("The FFmpeg program can not be downloaded! Check your connection.")
|
|
5722
|
+
QMessageBox.warning(
|
|
5723
|
+
None,
|
|
5724
|
+
cfg.programName,
|
|
5725
|
+
"The FFmpeg program can not be downloaded!\nCheck your connection.",
|
|
5726
|
+
QMessageBox.Ok | QMessageBox.Default,
|
|
5727
|
+
QMessageBox.NoButton,
|
|
5728
|
+
)
|
|
5729
|
+
sys.exit(3)
|
|
5730
|
+
|
|
5731
|
+
logging.info(f"File downloaded as {local_filename}")
|
|
5732
|
+
|
|
5733
|
+
# re-test for ffmpeg
|
|
5734
|
+
ret, msg = util.check_ffmpeg_path()
|
|
5735
|
+
|
|
5736
|
+
if ret:
|
|
5737
|
+
ffmpeg_bin = msg
|
|
5738
|
+
else:
|
|
5727
5739
|
QMessageBox.critical(
|
|
5728
5740
|
None,
|
|
5729
5741
|
cfg.programName,
|
|
@@ -5732,8 +5744,17 @@ def main():
|
|
|
5732
5744
|
QMessageBox.NoButton,
|
|
5733
5745
|
)
|
|
5734
5746
|
sys.exit(3)
|
|
5735
|
-
|
|
5736
|
-
|
|
5747
|
+
|
|
5748
|
+
# splashscreen
|
|
5749
|
+
# no splashscreen for Mac because it can mask the first use dialog box
|
|
5750
|
+
if (not options.nosplashscreen) and (sys.platform != "darwin"):
|
|
5751
|
+
start = time.time()
|
|
5752
|
+
splash = QSplashScreen(QPixmap(":/splash"))
|
|
5753
|
+
splash.show()
|
|
5754
|
+
splash.raise_()
|
|
5755
|
+
app.processEvents()
|
|
5756
|
+
while time.time() - start < 1:
|
|
5757
|
+
time.sleep(0.001)
|
|
5737
5758
|
|
|
5738
5759
|
app.setApplicationName(cfg.programName)
|
|
5739
5760
|
|
boris/dialog.py
CHANGED
|
@@ -26,7 +26,6 @@ import logging
|
|
|
26
26
|
import math
|
|
27
27
|
import pathlib as pl
|
|
28
28
|
import platform
|
|
29
|
-
import subprocess
|
|
30
29
|
import sys
|
|
31
30
|
import traceback
|
|
32
31
|
from typing import Union
|
|
@@ -98,29 +97,11 @@ def global_error_message(exception_type, exception_value, traceback_object):
|
|
|
98
97
|
Global error management
|
|
99
98
|
save error using loggin.critical and stdout
|
|
100
99
|
"""
|
|
101
|
-
import PySide6
|
|
102
|
-
|
|
103
|
-
error_text: str = (
|
|
104
|
-
f"BORIS version: {version.__version__}\n"
|
|
105
|
-
f"OS: {platform.uname().system} {platform.uname().release} {platform.uname().version}\n"
|
|
106
|
-
f"CPU: {platform.uname().machine} {platform.uname().processor}\n"
|
|
107
|
-
f"Python {platform.python_version()} ({'64-bit' if sys.maxsize > 2**32 else '32-bit'})\n"
|
|
108
|
-
f"Qt {qVersion()} - PySide {PySide6.__version__}\n"
|
|
109
|
-
f"MPV library version: {util.mpv_lib_version()[0]}\n"
|
|
110
|
-
f"MPV API version: {util.mpv_lib_version()[2]}\n"
|
|
111
|
-
f"MPV library file path: {util.mpv_lib_version()[1]}\n\n"
|
|
112
|
-
f"Error succeded at {dt.datetime.now():%Y-%m-%d %H:%M}\n\n"
|
|
113
|
-
)
|
|
114
|
-
error_text += "".join(traceback.format_exception(exception_type, exception_value, traceback_object))
|
|
115
100
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if sys.platform.startswith("linux"):
|
|
121
|
-
systeminfo = subprocess.getoutput("cat /etc/*rel*; uname -a")
|
|
122
|
-
|
|
123
|
-
error_text += f"\n\nSystem info\n===========\n\n{systeminfo}"
|
|
101
|
+
error_text = "\n\nSystem info\n===========\n\n"
|
|
102
|
+
error_text += util.get_systeminfo()
|
|
103
|
+
error_text += f"Error succeded at {dt.datetime.now():%Y-%m-%d %H:%M}\n\n"
|
|
104
|
+
error_text += "".join(traceback.format_exception(exception_type, exception_value, traceback_object))
|
|
124
105
|
|
|
125
106
|
# write to stdout
|
|
126
107
|
logging.critical(error_text)
|
|
@@ -129,8 +110,6 @@ def global_error_message(exception_type, exception_value, traceback_object):
|
|
|
129
110
|
try:
|
|
130
111
|
with open(pl.Path.home() / "boris_error.log", "w") as f_error:
|
|
131
112
|
f_error.write(error_text)
|
|
132
|
-
f_error.write("\nSystem info:\n")
|
|
133
|
-
f_error.write(systeminfo + "\n")
|
|
134
113
|
except Exception:
|
|
135
114
|
logging.critical(f"Impossible to write to {pl.Path.home() / 'boris_error.log'}")
|
|
136
115
|
|
boris/utilities.py
CHANGED
|
@@ -19,54 +19,101 @@ Copyright 2012-2025 Olivier Friard
|
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
+
from decimal import Decimal as dec
|
|
23
|
+
from decimal import getcontext, ROUND_DOWN
|
|
24
|
+
from hachoir.metadata import extractMetadata
|
|
25
|
+
from hachoir.parser import createParser
|
|
26
|
+
from shutil import copyfile
|
|
27
|
+
from typing import Union, Tuple
|
|
22
28
|
import csv
|
|
29
|
+
import datetime
|
|
23
30
|
import datetime as dt
|
|
31
|
+
import exifread
|
|
24
32
|
import json
|
|
25
33
|
import logging
|
|
26
34
|
import math
|
|
35
|
+
import numpy as np
|
|
27
36
|
import os
|
|
28
37
|
import pathlib as pl
|
|
38
|
+
from PIL.ImageQt import Image
|
|
39
|
+
import platform
|
|
29
40
|
import re
|
|
41
|
+
import shutil
|
|
30
42
|
import subprocess
|
|
31
43
|
import sys
|
|
32
44
|
import urllib.parse
|
|
45
|
+
import urllib.request
|
|
33
46
|
import wave
|
|
34
|
-
import exifread
|
|
35
|
-
import datetime
|
|
36
|
-
from decimal import Decimal as dec
|
|
37
|
-
from decimal import getcontext, ROUND_DOWN
|
|
38
|
-
from shutil import copyfile
|
|
39
|
-
from typing import Union, Tuple
|
|
40
47
|
|
|
41
|
-
from
|
|
42
|
-
from hachoir.metadata import extractMetadata
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
import numpy as np
|
|
48
|
+
from PySide6 import __version__ as pyside6_version
|
|
46
49
|
from PySide6.QtGui import QPixmap, QImage
|
|
47
|
-
|
|
48
|
-
from PIL.ImageQt import Image
|
|
50
|
+
from PySide6.QtCore import qVersion
|
|
49
51
|
|
|
50
52
|
from . import config as cfg
|
|
53
|
+
from . import version
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
logger = logging.getLogger(__name__)
|
|
53
56
|
|
|
54
|
-
"""
|
|
55
57
|
try:
|
|
56
58
|
from . import mpv2 as mpv
|
|
59
|
+
except Exception:
|
|
60
|
+
logger.warning("MPV library not found")
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
if sys.platform.startswith("win"):
|
|
63
|
+
import ctypes
|
|
64
|
+
|
|
65
|
+
ctypes.windll.user32.MessageBoxW(0, "The MPV library was not found!\nIt will be downloaded.", "BORIS", 0)
|
|
66
|
+
|
|
67
|
+
# download libmpv2.dll and ffprobe from https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/
|
|
68
|
+
|
|
69
|
+
url = "https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/"
|
|
70
|
+
|
|
71
|
+
external_files_dir = ""
|
|
72
|
+
# search where to download libmpv-2.dll
|
|
73
|
+
|
|
74
|
+
external_files_dir = pl.Path(__file__).parent / "misc"
|
|
75
|
+
if not external_files_dir.is_dir():
|
|
76
|
+
logger.info(f"Creating {external_files_dir} directory")
|
|
77
|
+
external_files_dir.mkdir(parents=True, exist_ok=True)
|
|
78
|
+
|
|
79
|
+
logger.info(f"MPV library directory: {external_files_dir}")
|
|
80
|
+
|
|
81
|
+
local_filename = external_files_dir / "libmpv-2.dll"
|
|
82
|
+
logger.info("Downloading libmpv-2.dll...")
|
|
83
|
+
try:
|
|
84
|
+
urllib.request.urlretrieve(url + "libmpv-2.dll", local_filename)
|
|
85
|
+
logger.info(f"File downloaded as {local_filename}")
|
|
86
|
+
except Exception:
|
|
87
|
+
logger.critical("The MPV library can not be downloaded! Check your connection.")
|
|
88
|
+
ctypes.windll.user32.MessageBoxW(0, "The MPV library can not be downloaded!\nCheck your connection.", "BORIS", 0)
|
|
89
|
+
sys.exit(5)
|
|
90
|
+
# reload package
|
|
91
|
+
try:
|
|
92
|
+
from . import mpv2 as mpv
|
|
93
|
+
except Exception:
|
|
94
|
+
logger.warning("MPV library not found after dowloading")
|
|
95
|
+
sys.exit(5)
|
|
96
|
+
|
|
97
|
+
elif sys.platform.startswith("linux"):
|
|
98
|
+
text = (
|
|
99
|
+
"The MPV library was not found!\nInstall it\n\n"
|
|
100
|
+
"With Debian/Ubuntu/Mint:\nsudo apt install libmpv2\n\n"
|
|
101
|
+
"With Fedora:\nsudo dnf install mpv-libs\n\n"
|
|
102
|
+
"With OpenSUSE:\nsudo zypper install mpv\n\n"
|
|
103
|
+
"Arch Linux / Manjaro:\nsudo pacman -S mpv\n\n"
|
|
104
|
+
)
|
|
105
|
+
if shutil.which("zenity") is not None:
|
|
106
|
+
subprocess.run(["zenity", "--error", f"--text={text}"])
|
|
107
|
+
elif shutil.which("kdialog"):
|
|
108
|
+
subprocess.run(["kdialog", "--msgbox", text])
|
|
109
|
+
elif shutil.which("gxmessage"):
|
|
110
|
+
subprocess.run(["gxmessage", text])
|
|
111
|
+
elif shutil.which("xmessage"):
|
|
112
|
+
subprocess.run(["xmessage", text])
|
|
113
|
+
|
|
114
|
+
sys.exit(5)
|
|
115
|
+
else:
|
|
116
|
+
sys.exit(5)
|
|
70
117
|
|
|
71
118
|
|
|
72
119
|
def extract_exif_DateTimeOriginal(file_path: str) -> int:
|
|
@@ -110,10 +157,10 @@ def extract_video_creation_date(file_path: str) -> int | None:
|
|
|
110
157
|
returns the timestamp of the media creation date time with Hachoir
|
|
111
158
|
"""
|
|
112
159
|
|
|
113
|
-
|
|
160
|
+
logger.debug(f"extract_video_creation_date for {file_path}")
|
|
114
161
|
|
|
115
162
|
if not pl.Path(file_path).is_file():
|
|
116
|
-
|
|
163
|
+
logger.debug(f"{file_path} not found")
|
|
117
164
|
return None
|
|
118
165
|
try:
|
|
119
166
|
parser = createParser(file_path)
|
|
@@ -140,14 +187,14 @@ def extract_date_time_from_file_name(file_path: str) -> int | None:
|
|
|
140
187
|
|
|
141
188
|
if matches:
|
|
142
189
|
if pattern == r"\d{4}-\d{2}-\d{2}_\d{6}":
|
|
143
|
-
|
|
190
|
+
logger.debug(
|
|
144
191
|
f"extract_date_time_from_file_name timestamp from {file_path}: {int(datetime.datetime.strptime(matches[0], '%Y-%m-%d_%H%M%S').timestamp())}"
|
|
145
192
|
)
|
|
146
193
|
|
|
147
194
|
return int(datetime.datetime.strptime(matches[0], "%Y-%m-%d_%H%M%S").timestamp())
|
|
148
195
|
|
|
149
196
|
if pattern == r"\d{4}-\d{2}-\d{2}_\d{2}:\d{2}:\d{2}":
|
|
150
|
-
|
|
197
|
+
logger.debug(
|
|
151
198
|
f"extract_date_time_from_file_name timestamp from {file_path}: {int(datetime.datetime.strptime(matches[0], '%Y-%m-%d_%H:%M:%S').timestamp())}"
|
|
152
199
|
)
|
|
153
200
|
|
|
@@ -798,9 +845,9 @@ def extract_wav(ffmpeg_bin: str, media_file_path: str, tmp_dir: str) -> str:
|
|
|
798
845
|
try:
|
|
799
846
|
wav = wave.open(media_file_path, "r")
|
|
800
847
|
wav.close()
|
|
801
|
-
|
|
848
|
+
logger.debug(f"{media_file_path} is a WAV file. Copying in the temp directory...")
|
|
802
849
|
copyfile(media_file_path, wav_file_path)
|
|
803
|
-
|
|
850
|
+
logger.debug(f"{media_file_path} copied in {wav_file_path}")
|
|
804
851
|
return str(wav_file_path)
|
|
805
852
|
except Exception:
|
|
806
853
|
if wav_file_path.is_file():
|
|
@@ -815,7 +862,7 @@ def extract_wav(ffmpeg_bin: str, media_file_path: str, tmp_dir: str) -> str:
|
|
|
815
862
|
)
|
|
816
863
|
out, error = p.communicate()
|
|
817
864
|
out, error = out.decode("utf-8"), error.decode("utf-8")
|
|
818
|
-
|
|
865
|
+
logger.debug(f"{out}, {error}")
|
|
819
866
|
|
|
820
867
|
if "does not contain any stream" not in error:
|
|
821
868
|
if wav_file_path.is_file():
|
|
@@ -866,8 +913,8 @@ def seconds_of_day(timestamp: dt.datetime) -> dec:
|
|
|
866
913
|
dev: number of seconds since the start of the day
|
|
867
914
|
"""
|
|
868
915
|
|
|
869
|
-
#
|
|
870
|
-
#
|
|
916
|
+
# logger.debug("function: seconds_of_day")
|
|
917
|
+
# logger.debug(f"{timestamp = }")
|
|
871
918
|
|
|
872
919
|
t = timestamp.time()
|
|
873
920
|
return dec(t.hour * 3600 + t.minute * 60 + t.second + t.microsecond / 1000000).quantize(dec("0.001"))
|
|
@@ -1200,8 +1247,8 @@ def test_ffmpeg_path(FFmpegPath: str) -> Tuple[bool, str]:
|
|
|
1200
1247
|
"""
|
|
1201
1248
|
|
|
1202
1249
|
out, error = subprocess.Popen(f'"{FFmpegPath}" -version', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
|
|
1203
|
-
|
|
1204
|
-
|
|
1250
|
+
logger.debug(f"test ffmpeg path output: {out}")
|
|
1251
|
+
logger.debug(f"test ffmpeg path error: {error}")
|
|
1205
1252
|
|
|
1206
1253
|
if (b"avconv" in out) or (b"the Libav developers" in error):
|
|
1207
1254
|
return False, "Please use FFmpeg from https://www.ffmpeg.org in place of FFmpeg from Libav project."
|
|
@@ -1223,43 +1270,24 @@ def check_ffmpeg_path() -> Tuple[bool, str]:
|
|
|
1223
1270
|
str: if bool True returns ffmpegpath else returns error message
|
|
1224
1271
|
"""
|
|
1225
1272
|
|
|
1273
|
+
# search embedded ffmpeg
|
|
1226
1274
|
if sys.platform.startswith("linux") or sys.platform.startswith("darwin"):
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
ffmpeg_path = pl.Path(sys.argv[0]).resolve().parent / "boris" / "misc" / "ffmpeg"
|
|
1231
|
-
if sys.argv[0].endswith("__main__.py"):
|
|
1232
|
-
ffmpeg_path = pl.Path(sys.argv[0]).resolve().parent / "misc" / "ffmpeg"
|
|
1233
|
-
|
|
1234
|
-
if not ffmpeg_path.is_file():
|
|
1235
|
-
# search global ffmpeg
|
|
1236
|
-
ffmpeg_path = "ffmpeg"
|
|
1237
|
-
|
|
1238
|
-
# test ffmpeg
|
|
1239
|
-
r, msg = test_ffmpeg_path(str(ffmpeg_path))
|
|
1240
|
-
if r:
|
|
1241
|
-
return True, str(ffmpeg_path)
|
|
1242
|
-
else:
|
|
1243
|
-
return False, "FFmpeg is not available"
|
|
1275
|
+
ffmpeg_executable = pl.Path("ffmpeg")
|
|
1276
|
+
elif sys.platform.startswith("win"):
|
|
1277
|
+
ffmpeg_executable = pl.Path("ffmpeg.exe")
|
|
1244
1278
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
# test ffmpeg
|
|
1258
|
-
r, msg = test_ffmpeg_path(str(ffmpeg_path))
|
|
1259
|
-
if r:
|
|
1260
|
-
return True, str(ffmpeg_path)
|
|
1261
|
-
else:
|
|
1262
|
-
return False, "FFmpeg is not available"
|
|
1279
|
+
ffmpeg_path = pl.Path(__file__).parent / "misc" / ffmpeg_executable
|
|
1280
|
+
|
|
1281
|
+
if not ffmpeg_path.is_file():
|
|
1282
|
+
# search global ffmpeg
|
|
1283
|
+
ffmpeg_path = ffmpeg_executable
|
|
1284
|
+
|
|
1285
|
+
# test ffmpeg
|
|
1286
|
+
r, msg = test_ffmpeg_path(str(ffmpeg_path))
|
|
1287
|
+
if r:
|
|
1288
|
+
return True, str(ffmpeg_path)
|
|
1289
|
+
else:
|
|
1290
|
+
return False, "FFmpeg is not available"
|
|
1263
1291
|
|
|
1264
1292
|
|
|
1265
1293
|
def smart_size_format(n: Union[float, int, str, None]) -> str:
|
|
@@ -1281,6 +1309,73 @@ def smart_size_format(n: Union[float, int, str, None]) -> str:
|
|
|
1281
1309
|
return f"{n / 1_000_000_000:,.1f} Gb"
|
|
1282
1310
|
|
|
1283
1311
|
|
|
1312
|
+
def get_systeminfo() -> str:
|
|
1313
|
+
"""
|
|
1314
|
+
returns info about the system
|
|
1315
|
+
"""
|
|
1316
|
+
|
|
1317
|
+
mpv_lib_version_, mpv_lib_file_path, mpv_api_version = mpv_lib_version()
|
|
1318
|
+
|
|
1319
|
+
system_info = (
|
|
1320
|
+
f"BORIS version: {version.__version__}\n"
|
|
1321
|
+
f"OS: {platform.uname().system} {platform.uname().release} {platform.uname().version}\n"
|
|
1322
|
+
f"CPU: {platform.uname().machine} {platform.uname().processor}\n"
|
|
1323
|
+
f"Python {platform.python_version()} ({'64-bit' if sys.maxsize > 2**32 else '32-bit'})\n"
|
|
1324
|
+
f"Qt {qVersion()} - PySide {pyside6_version}\n"
|
|
1325
|
+
f"MPV library version: {mpv_lib_version_}\n"
|
|
1326
|
+
f"MPV API version: {mpv_api_version}\n"
|
|
1327
|
+
f"MPV library file path: {mpv_lib_file_path}\n\n"
|
|
1328
|
+
)
|
|
1329
|
+
|
|
1330
|
+
r, memory = mem_info()
|
|
1331
|
+
if not r:
|
|
1332
|
+
system_info += (
|
|
1333
|
+
f"Memory (RAM) Total: {memory.get('total_memory', 'Not available'):.2f} Mb "
|
|
1334
|
+
f"Free: {memory.get('free_memory', 'Not available'):.2f} Mb\n\n"
|
|
1335
|
+
)
|
|
1336
|
+
|
|
1337
|
+
return system_info
|
|
1338
|
+
|
|
1339
|
+
"""
|
|
1340
|
+
# system info
|
|
1341
|
+
systeminfo = ""
|
|
1342
|
+
if sys.platform.startswith("win"):
|
|
1343
|
+
# systeminfo = subprocess.getoutput("systeminfo")
|
|
1344
|
+
systeminfo = subprocess.run("systeminfo /FO csv /NH", capture_output=True, text=True, encoding="mbcs", shell=True).stdout
|
|
1345
|
+
|
|
1346
|
+
import csv
|
|
1347
|
+
from io import StringIO
|
|
1348
|
+
|
|
1349
|
+
# Parse it as CSV
|
|
1350
|
+
f = StringIO(systeminfo)
|
|
1351
|
+
reader = csv.reader(f)
|
|
1352
|
+
parsed_data = list(reader)[0]
|
|
1353
|
+
# Print specific fields by index
|
|
1354
|
+
info_to_show = ""
|
|
1355
|
+
info_to_show += f"Computer Name: {parsed_data[0]}\n"
|
|
1356
|
+
info_to_show += f"OS Name: {parsed_data[1]}\n"
|
|
1357
|
+
info_to_show += f"OS Version: {parsed_data[2]}\n"
|
|
1358
|
+
info_to_show += f"System Manufacturer: {parsed_data[11]}\n"
|
|
1359
|
+
info_to_show += f"System Model: {parsed_data[12]}\n"
|
|
1360
|
+
info_to_show += f"Processor: {parsed_data[14]}\n"
|
|
1361
|
+
info_to_show += f"Locale: {parsed_data[19]}\n"
|
|
1362
|
+
info_to_show += f"Installed Memory: {parsed_data[22]}\n"
|
|
1363
|
+
|
|
1364
|
+
# info about graphic card
|
|
1365
|
+
graphic_info = subprocess.run(
|
|
1366
|
+
"wmic path win32_videocontroller get name", capture_output=True, text=True, encoding="mbcs", shell=True
|
|
1367
|
+
).stdout
|
|
1368
|
+
info_to_show += graphic_info.replace("\n", "").replace("Name", "Graphic card model")
|
|
1369
|
+
|
|
1370
|
+
systeminfo = info_to_show
|
|
1371
|
+
|
|
1372
|
+
if sys.platform.startswith("linux"):
|
|
1373
|
+
systeminfo = subprocess.getoutput("cat /etc/*rel*; uname -a")
|
|
1374
|
+
|
|
1375
|
+
return systeminfo
|
|
1376
|
+
"""
|
|
1377
|
+
|
|
1378
|
+
|
|
1284
1379
|
def ffprobe_media_analysis(ffmpeg_bin: str, file_name: str) -> dict:
|
|
1285
1380
|
"""
|
|
1286
1381
|
analyse video parameters with ffprobe (if available)
|
|
@@ -1436,8 +1531,8 @@ def accurate_media_analysis(ffmpeg_bin: str, file_name: str) -> dict:
|
|
|
1436
1531
|
|
|
1437
1532
|
ffprobe_results = ffprobe_media_analysis(ffmpeg_bin, file_name)
|
|
1438
1533
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1534
|
+
logger.debug(f"file_name: {file_name}")
|
|
1535
|
+
logger.debug(f"ffprobe_results: {ffprobe_results}")
|
|
1441
1536
|
|
|
1442
1537
|
if ("error" not in ffprobe_results) and (ffprobe_results["bitrate"] is not None):
|
|
1443
1538
|
return ffprobe_results
|
boris/version.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
boris/1.py,sha256=rb6Nstw1vIHlBwMnzExVOlgU2F75Tuf1VYRXBTrZUFg,1082
|
|
1
2
|
boris/__init__.py,sha256=iAtmVMy22TJpMmxVTMSK_6-wXnCbx1ogvWgfYEcbHzU,773
|
|
2
3
|
boris/__main__.py,sha256=ANjTbXgXDoz2nB1tCtOIllfIVotCa602iebACX7rXaE,764
|
|
3
|
-
boris/about.py,sha256=
|
|
4
|
+
boris/about.py,sha256=VPa8zeu0bMb1LRXDq8uUSG_7mSbkb2HTk1AtWbzWQwE,5366
|
|
4
5
|
boris/add_modifier.py,sha256=DWqxkKDBm21QH_kPvhpnltwLtFvPxne0VmZ1SY26hj8,26340
|
|
5
6
|
boris/add_modifier_ui.py,sha256=Y7TLO5uS6zW7zpjXmjA4V_VIp_bFDNtjOTbJ9Q6m-mQ,11601
|
|
6
7
|
boris/advanced_event_filtering.py,sha256=VlvU12mL6xYacZOvJAi5uLpHMcmAw5Pvuvmka-PN29c,15469
|
|
@@ -11,17 +12,17 @@ boris/boris_cli.py,sha256=n0OiVvZM1gM6E7yKaff9wlgmpAGK4TK052VRi8AabJo,13196
|
|
|
11
12
|
boris/cmd_arguments.py,sha256=oWb-FvhKLbKJhATlTHy9muWu8XnnUfOZ-3Fmz2M8Yzc,1848
|
|
12
13
|
boris/coding_pad.py,sha256=fBKdp7DDyupySJosIYtqNd8s2E-GruzCgVhDFsoVWKE,10986
|
|
13
14
|
boris/config.py,sha256=PQXm3gJgdCtPOFKLH65sDGw8sk_cdMP53p6eMrlRJl0,17457
|
|
14
|
-
boris/config_file.py,sha256=
|
|
15
|
+
boris/config_file.py,sha256=bPDDRjtylVJ2ll-FNRjME5iIsIagonZNFns-k9kGW2Q,13545
|
|
15
16
|
boris/connections.py,sha256=rVI18AuXh8cEnnoCKJk0RMWAaiNOpiaS554Okgk3SBY,19383
|
|
16
|
-
boris/converters.py,sha256=
|
|
17
|
+
boris/converters.py,sha256=n6gDM9x2hS-ZOoHLruiifuXxnC7ERsUukiFokhHZPoQ,11678
|
|
17
18
|
boris/converters_ui.py,sha256=uu7LOBV_fKv2DBdOqsqPwjGsjgONr5ODBoscAA-EP48,9900
|
|
18
19
|
boris/cooccurence.py,sha256=tVERC-V8MWjWHlGEfDuu08iS94qjt4do-38jwI62QaY,10367
|
|
19
|
-
boris/core.py,sha256=
|
|
20
|
+
boris/core.py,sha256=jMZkM_VsFD-Yk6Q-8wApWZfo-JKvmvpQo5lY1H_k7Bc,231590
|
|
20
21
|
boris/core_qrc.py,sha256=J0kom27nrmi4-TCDLJZCZbtUAitiXQ4WEDfErawuxt8,639879
|
|
21
22
|
boris/core_ui.py,sha256=SeC26uveDCjrCBLsRPuQ6FaapKfON_HIRcQStEDLhl4,76384
|
|
22
23
|
boris/db_functions.py,sha256=Uw9wWH_Pe-qNzpV1k21YG_jKsoOmfY_iiK_7ARZHGDc,13352
|
|
23
24
|
boris/dev.py,sha256=9pUElbjl9g17rFUJXX5aVSu55_iIKIuDxNdrB0DI_d0,3671
|
|
24
|
-
boris/dialog.py,sha256=
|
|
25
|
+
boris/dialog.py,sha256=LqZ73R9cwiL4qzKyMxeS2G8PKnbVZ0xFvZHw-oSek0M,34039
|
|
25
26
|
boris/duration_widget.py,sha256=GjZgCAMGOcsNjoPiRImEVe6yMkH2vuNoh44ulpd5nlg,6924
|
|
26
27
|
boris/edit_event.py,sha256=IMZnopPALNJHgGenl_kMZjqO_Q9GKtyEcyVq5w5VGyU,8001
|
|
27
28
|
boris/edit_event_ui.py,sha256=qFgt00cejGB6UGC1mFkyZcsIAdvMeYMK0WYjZtJl1T0,9207
|
|
@@ -77,8 +78,8 @@ boris/synthetic_time_budget.py,sha256=3Eb9onMLmgqCLd50CuxV9L8RV2ESzfaMWvPK_bXUMM
|
|
|
77
78
|
boris/time_budget_functions.py,sha256=y5He8crz0xsTxVfz0jATwFFQVnPAIrNHja_0sF6NtRE,52551
|
|
78
79
|
boris/time_budget_widget.py,sha256=z-tyITBtIz-KH1H2OdMB5a8x9QQLK7Wu96-zkC6NVDA,43213
|
|
79
80
|
boris/transitions.py,sha256=_aZJfJWv3EBrtmQ7qsdTCayQo6uWU7BXqtQQgflEhr4,12250
|
|
80
|
-
boris/utilities.py,sha256=
|
|
81
|
-
boris/version.py,sha256=
|
|
81
|
+
boris/utilities.py,sha256=suquxdukTUscCy2M3fbR2-OcFtf_vrx4HcQD3i18XYo,56502
|
|
82
|
+
boris/version.py,sha256=elwA5lNbiLkILJCCD7leDvgwYJgZb2gk3T__Uou8fSE,785
|
|
82
83
|
boris/video_equalizer.py,sha256=FartoGghFK-T53zklP70rPKYqTuzL8qdvfGlsOF2wwc,5854
|
|
83
84
|
boris/video_equalizer_ui.py,sha256=1CG3s79eM4JAbaCx3i1ILZXLceb41_gGXlOLNfpBgnw,10142
|
|
84
85
|
boris/video_operations.py,sha256=mh3iR__Sm2KnV44L_sW2pOo3AgLwlM7wiTnnqQiAVs4,9381
|
|
@@ -96,9 +97,9 @@ boris/portion/dict.py,sha256=SyHxc7PfDw2ufNLFQycwJtzmRfL48rDp4UrM2KN7IWc,11282
|
|
|
96
97
|
boris/portion/func.py,sha256=3TkQtFKLfsqntwd27HSGHceFhnXHmT-EbNMqktElC5Q,2174
|
|
97
98
|
boris/portion/interval.py,sha256=bAdUiJjGeUAPgsBAImwNeviiwfQq5odfhFZccAWzOTA,20299
|
|
98
99
|
boris/portion/io.py,sha256=ppNeRpiLNrocF1yzGeuEUIhYMf2LfsR-cji3d0nmvUs,6371
|
|
99
|
-
boris_behav_obs-9.
|
|
100
|
-
boris_behav_obs-9.
|
|
101
|
-
boris_behav_obs-9.
|
|
102
|
-
boris_behav_obs-9.
|
|
103
|
-
boris_behav_obs-9.
|
|
104
|
-
boris_behav_obs-9.
|
|
100
|
+
boris_behav_obs-9.4.dist-info/licenses/LICENSE.TXT,sha256=WJ7YI-moTFb-uVrFjnzzhGJrnL9P2iqQe8NuED3hutI,35141
|
|
101
|
+
boris_behav_obs-9.4.dist-info/METADATA,sha256=R-ofdWjXC79DgAjKwE-GeB8n_rJBD9uUSnvdo3_3SmI,4512
|
|
102
|
+
boris_behav_obs-9.4.dist-info/WHEEL,sha256=_z0Kb-VmhLeNt2nZ-PsoQBjD25rP0tBwgAyRYD7oTKI,109
|
|
103
|
+
boris_behav_obs-9.4.dist-info/entry_points.txt,sha256=k__8XvFi4vaA4QFvQehCZjYkKmZH34HSAJI2iYCWrMs,52
|
|
104
|
+
boris_behav_obs-9.4.dist-info/top_level.txt,sha256=fJSgm62S7WesiwTorGbOO4nNN0yzgZ3klgfGi3Px4qI,6
|
|
105
|
+
boris_behav_obs-9.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|