Skip to content

Commit 298dbf0

Browse files
authored
Fix for preference window size (#1677)
1 parent eadf4ec commit 298dbf0

4 files changed

Lines changed: 86 additions & 4 deletions

File tree

‎buzz/widgets/preferences_dialog/preferences_dialog.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,5 @@ def __init__(
7676

7777
self.setLayout(layout)
7878

79-
self.setMinimumHeight(500)
79+
self.setMinimumHeight(750)
8080
self.setMinimumWidth(650)

‎docs/docs/preferences.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,30 @@ larger model. For example `q_5` version. Whisper.cpp base models in different qu
6969

7070
[![Model preferences](https://raw.githubusercontent.com/chidiwilliams/buzz/main/share/screenshots/buzz-3.2-model-preferences.png)](https://www.loom.com/share/cf263b099ac3481082bb56d19b7c87fe "Model preferences")
7171

72+
## Folder Watch Preferences
73+
74+
Folder watch lets Buzz transcribe audio and video files automatically. Buzz watches a folder and
75+
transcribes every new media file that appears in it, while Buzz is running.
76+
77+
**Enable folder watch** - Turns folder watch on or off. The other options are available only when it is enabled.
78+
79+
**Input folder** - Folder to watch for new files. Subfolders are watched too. Hidden files and folders are ignored.
80+
Buzz waits until a file has stopped changing for about 30 seconds before transcribing it, so files
81+
that are still being copied are not transcribed too early.
82+
83+
**Output folder** - Folder where transcripts are saved. After transcription the original file is
84+
moved here as well, so it is not transcribed again. The subfolder structure of the input folder is
85+
kept. The output folder cannot be the input folder or a subfolder of it.
86+
87+
**Delete processed files** - Deletes the original file after transcription instead of moving it to
88+
the output folder. Audio playback will not be available for these transcriptions.
89+
90+
**Transcription options** - Model, task, language and export formats to use for the files found in
91+
the watched folder. They work the same way as for a regular file transcription.
92+
93+
**Speaker identification** - When enabled, speakers are identified after transcription and speaker
94+
labels are added to the exported transcripts. Transcription will take longer.
95+
7296
## Advanced Preferences
7397

7498
To keep preferences section simple for new users, some more advanced preferences are settable via OS environment variables. Set the necessary environment variables in your OS before starting Buzz or create a script to set them.

‎tests/conftest.py‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import gc
12
import glob
23
import multiprocessing
34
import os
@@ -21,7 +22,10 @@
2122
multiprocessing.set_start_method("spawn", force=True)
2223
except RuntimeError:
2324
pass # Already set
25+
from PyQt6 import sip
26+
from PyQt6.QtCore import QCoreApplication, QEvent, QObject, QThread
2427
from PyQt6.QtSql import QSqlDatabase
28+
from PyQt6.QtWidgets import QApplication
2529
from _pytest.fixtures import SubRequest
2630

2731
from buzz.db.dao.transcription_dao import TranscriptionDAO
@@ -33,6 +37,60 @@
3337
from buzz.widgets.application import Application
3438

3539

40+
def pytest_sessionfinish(session, exitstatus):
41+
"""Destroy Qt objects left over by the tests while the QApplication is alive.
42+
43+
At interpreter exit PyQt deletes every parentless QObject still owned by
44+
Python while walking sip's wrapper map. Deleting one of them can run Python
45+
code that creates or frees wrappers, which changes the map mid-walk and
46+
segfaults the run after all tests have passed. Deleting the leftovers here,
47+
from a snapshot, leaves nothing for that exit walk to do.
48+
"""
49+
app = QApplication.instance()
50+
if app is None:
51+
return
52+
53+
for widget in app.topLevelWidgets():
54+
widget.close()
55+
widget.deleteLater()
56+
QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete)
57+
gc.collect()
58+
59+
leftovers = []
60+
for obj in gc.get_objects():
61+
try:
62+
if (
63+
isinstance(obj, QObject)
64+
and obj is not app
65+
and not sip.isdeleted(obj)
66+
and sip.ispyowned(obj)
67+
and obj.parent() is None
68+
):
69+
leftovers.append(obj)
70+
except RuntimeError:
71+
pass
72+
73+
# Threads must be stopped before deletion, Qt aborts on deleting a running one
74+
for obj in leftovers:
75+
if isinstance(obj, QThread) and not sip.isdeleted(obj):
76+
obj.quit()
77+
obj.wait(5_000)
78+
79+
main_thread = sip.unwrapinstance(QThread.currentThread())
80+
for obj in leftovers:
81+
if sip.isdeleted(obj):
82+
continue
83+
# Objects living in a still running worker thread can't be safely deleted from here
84+
thread = obj.thread()
85+
if thread is not None and sip.unwrapinstance(thread) != main_thread and thread.isRunning():
86+
continue
87+
if isinstance(obj, QThread) and obj.isRunning():
88+
continue
89+
sip.delete(obj)
90+
leftovers.clear()
91+
gc.collect()
92+
93+
3694
@pytest.fixture()
3795
def db(qapp) -> QSqlDatabase:
3896
# Qt's SQL module needs a QCoreApplication to be alive; opening a

‎uv.lock‎

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)