Slideshow: video support, seek keys, fix double audio
- Slideshow mode now supports video (webm/mp4) and GIFs - Arrow keys navigate posts in both preview and slideshow (including videos) - , and . seek 5s back/forward in videos - Main preview video pauses when slideshow opens (no double audio) - Fix focus stealing by video player widgets in slideshow
This commit is contained in:
parent
238df9cf3e
commit
d275809c6b
@ -703,8 +703,9 @@ class BooruApp(QMainWindow):
|
||||
idx = self._grid.selected_index
|
||||
if 0 <= idx < len(self._grid._thumbs):
|
||||
self._grid._thumbs[idx]._cached_path = path
|
||||
# Update fullscreen if open
|
||||
# Update fullscreen if open, and mute the main player
|
||||
if self._fullscreen_window and self._fullscreen_window.isVisible():
|
||||
self._preview._video_player.stop()
|
||||
self._fullscreen_window.set_media(path, info)
|
||||
|
||||
def _on_favorite_selected(self, fav) -> None:
|
||||
@ -802,15 +803,22 @@ class BooruApp(QMainWindow):
|
||||
path = self._preview._current_path
|
||||
if not path:
|
||||
return
|
||||
# Pause the main preview's video player
|
||||
self._preview._video_player.stop()
|
||||
from .preview import FullscreenPreview
|
||||
self._fullscreen_window = FullscreenPreview(parent=self)
|
||||
self._fullscreen_window.navigate.connect(self._navigate_fullscreen)
|
||||
self._fullscreen_window.destroyed.connect(self._on_fullscreen_closed)
|
||||
self._fullscreen_window.set_media(path, self._preview._info_label.text())
|
||||
|
||||
def _on_fullscreen_closed(self) -> None:
|
||||
self._fullscreen_window = None
|
||||
|
||||
def _navigate_fullscreen(self, direction: int) -> None:
|
||||
self._navigate_preview(direction)
|
||||
# For synchronous loads (cached/favorites), update immediately
|
||||
if self._fullscreen_window and self._preview._current_path:
|
||||
self._preview._video_player.stop()
|
||||
self._fullscreen_window.set_media(
|
||||
self._preview._current_path,
|
||||
self._preview._info_label.text(),
|
||||
|
||||
@ -23,26 +23,52 @@ def _is_video(path: str) -> bool:
|
||||
|
||||
|
||||
class FullscreenPreview(QMainWindow):
|
||||
"""Fullscreen image viewer window with navigation."""
|
||||
"""Fullscreen media viewer with navigation — images, GIFs, and video."""
|
||||
|
||||
navigate = Signal(int) # -1 = prev, +1 = next
|
||||
|
||||
def __init__(self, parent=None) -> None:
|
||||
super().__init__(parent, Qt.WindowType.Window)
|
||||
self.setWindowTitle("booru-viewer — Fullscreen")
|
||||
|
||||
self._stack = QStackedWidget()
|
||||
self.setCentralWidget(self._stack)
|
||||
|
||||
self._viewer = ImageViewer()
|
||||
self._viewer.close_requested.connect(self.close)
|
||||
self.setCentralWidget(self._viewer)
|
||||
self._stack.addWidget(self._viewer)
|
||||
|
||||
self._video = VideoPlayer()
|
||||
self._video.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
for child in self._video.findChildren(QWidget):
|
||||
child.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
self._stack.addWidget(self._video)
|
||||
|
||||
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
self.setFocus()
|
||||
self.showFullScreen()
|
||||
|
||||
def set_media(self, path: str, info: str = "") -> None:
|
||||
ext = Path(path).suffix.lower()
|
||||
if ext == ".gif":
|
||||
if _is_video(path):
|
||||
self._viewer.clear()
|
||||
self._video.stop()
|
||||
self._video.play_file(path, info)
|
||||
self._stack.setCurrentIndex(1)
|
||||
elif ext == ".gif":
|
||||
self._video.stop()
|
||||
self._viewer.set_gif(path, info)
|
||||
self._stack.setCurrentIndex(0)
|
||||
else:
|
||||
self._video.stop()
|
||||
pix = QPixmap(path)
|
||||
if not pix.isNull():
|
||||
self._viewer.set_image(pix, info)
|
||||
self._stack.setCurrentIndex(0)
|
||||
|
||||
def closeEvent(self, event) -> None:
|
||||
self._video.stop()
|
||||
super().closeEvent(event)
|
||||
|
||||
def keyPressEvent(self, event: QKeyEvent) -> None:
|
||||
if event.key() in (Qt.Key.Key_Escape, Qt.Key.Key_Q):
|
||||
@ -51,6 +77,12 @@ class FullscreenPreview(QMainWindow):
|
||||
self.navigate.emit(-1)
|
||||
elif event.key() in (Qt.Key.Key_Right, Qt.Key.Key_L):
|
||||
self.navigate.emit(1)
|
||||
elif event.key() == Qt.Key.Key_Space and self._stack.currentIndex() == 1:
|
||||
self._video._toggle_play()
|
||||
elif event.key() == Qt.Key.Key_Period and self._stack.currentIndex() == 1:
|
||||
self._video._seek_relative(5000)
|
||||
elif event.key() == Qt.Key.Key_Comma and self._stack.currentIndex() == 1:
|
||||
self._video._seek_relative(-5000)
|
||||
else:
|
||||
super().keyPressEvent(event)
|
||||
|
||||
@ -294,6 +326,10 @@ class VideoPlayer(QWidget):
|
||||
def _seek(self, pos: int) -> None:
|
||||
self._player.setPosition(pos)
|
||||
|
||||
def _seek_relative(self, ms: int) -> None:
|
||||
pos = max(0, self._player.position() + ms)
|
||||
self._player.setPosition(pos)
|
||||
|
||||
def _set_volume(self, val: int) -> None:
|
||||
self._audio.setVolume(val / 100.0)
|
||||
|
||||
@ -497,6 +533,14 @@ class ImagePreview(QWidget):
|
||||
self._image_viewer.keyPressEvent(event)
|
||||
elif event.key() == Qt.Key.Key_Space:
|
||||
self._video_player._toggle_play()
|
||||
elif event.key() == Qt.Key.Key_Period:
|
||||
self._video_player._seek_relative(5000)
|
||||
elif event.key() == Qt.Key.Key_Comma:
|
||||
self._video_player._seek_relative(-5000)
|
||||
elif event.key() in (Qt.Key.Key_Left, Qt.Key.Key_H):
|
||||
self.navigate.emit(-1)
|
||||
elif event.key() in (Qt.Key.Key_Right, Qt.Key.Key_L):
|
||||
self.navigate.emit(1)
|
||||
|
||||
def resizeEvent(self, event) -> None:
|
||||
super().resizeEvent(event)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user