diff --git a/src/tagstudio/qt/resources.json b/src/tagstudio/qt/resources.json index 216b9a2b6..c2404889c 100644 --- a/src/tagstudio/qt/resources.json +++ b/src/tagstudio/qt/resources.json @@ -122,9 +122,5 @@ "thumb_loading": { "path": "qt/images/thumb_loading.png", "mode": "pil" - }, - "placeholder_mp4": { - "path": "qt/videos/placeholder.mp4", - "mode": "rb" } } diff --git a/src/tagstudio/qt/ts_qt.py b/src/tagstudio/qt/ts_qt.py index ff6d48567..adb0b0bb9 100644 --- a/src/tagstudio/qt/ts_qt.py +++ b/src/tagstudio/qt/ts_qt.py @@ -1010,7 +1010,7 @@ def delete_files_callback(self, origin_path: str | Path, origin_id: int | None = for i, tup in enumerate(pending): e_id, f = tup if (origin_path == f) or (not origin_path): - self.preview_panel.thumb.stop_file_use() + self.preview_panel.thumb.media_player.stop() if delete_file(self.lib.library_dir / f): self.main_window.statusbar.showMessage( Translations.format( diff --git a/src/tagstudio/qt/widgets/media_player.py b/src/tagstudio/qt/widgets/media_player.py index 807b66990..9d4eaf7b6 100644 --- a/src/tagstudio/qt/widgets/media_player.py +++ b/src/tagstudio/qt/widgets/media_player.py @@ -416,9 +416,9 @@ def has_video_changed(self, video_available: bool) -> None: self.scene().removeItem(self.video_preview) def stop(self) -> None: - """Clear the filepath and stop the player.""" + """Clear the filepath, stop the player and release the source.""" self.filepath = None - self.player.stop() + self.player.setSource(QUrl()) def play(self, filepath: Path) -> None: """Set the source of the QMediaPlayer and play.""" diff --git a/src/tagstudio/qt/widgets/preview/preview_thumb.py b/src/tagstudio/qt/widgets/preview/preview_thumb.py index 7440da827..4b3972267 100644 --- a/src/tagstudio/qt/widgets/preview/preview_thumb.py +++ b/src/tagstudio/qt/widgets/preview/preview_thumb.py @@ -4,8 +4,8 @@ import io import time -import typing from pathlib import Path +from typing import TYPE_CHECKING, override from warnings import catch_warnings import cv2 @@ -24,12 +24,11 @@ from tagstudio.qt.helpers.qbutton_wrapper import QPushButtonWrapper from tagstudio.qt.helpers.rounded_pixmap_style import RoundedPixmapStyle from tagstudio.qt.platform_strings import open_file_str, trash_term -from tagstudio.qt.resource_manager import ResourceManager from tagstudio.qt.translations import Translations from tagstudio.qt.widgets.media_player import MediaPlayer from tagstudio.qt.widgets.thumb_renderer import ThumbRenderer -if typing.TYPE_CHECKING: +if TYPE_CHECKING: from tagstudio.qt.ts_qt import QtDriver logger = structlog.get_logger(__name__) @@ -39,7 +38,7 @@ class PreviewThumb(QWidget): """The Preview Panel Widget.""" - def __init__(self, library: Library, driver: "QtDriver"): + def __init__(self, library: Library, driver: "QtDriver") -> None: super().__init__() self.is_connected = False @@ -54,6 +53,7 @@ def __init__(self, library: Library, driver: "QtDriver"): self.image_layout.setStackingMode(QStackedLayout.StackingMode.StackAll) self.image_layout.setContentsMargins(0, 0, 0, 0) + self.opener: FileOpenerHelper | None = None self.open_file_action = QAction(Translations["file.open_file"], self) self.open_explorer_action = QAction(open_file_str(), self) self.delete_action = QAction( @@ -133,17 +133,17 @@ def _set_mp_max_size(self, size: QSize) -> None: def _has_video_changed(self, video: bool) -> None: self.update_image_size((self.size().width(), self.size().height())) - def _stacked_page_setup(self, page: QWidget, widget: QWidget): + def _stacked_page_setup(self, page: QWidget, widget: QWidget) -> None: layout = QHBoxLayout(page) layout.addWidget(widget) layout.setAlignment(widget, Qt.AlignmentFlag.AlignCenter) layout.setContentsMargins(0, 0, 0, 0) page.setLayout(layout) - def set_image_ratio(self, ratio: float): + def set_image_ratio(self, ratio: float) -> None: self.image_ratio = ratio - def update_image_size(self, size: tuple[int, int], ratio: float | None = None): + def update_image_size(self, size: tuple[int, int], ratio: float | None = None) -> None: if ratio: self.set_image_ratio(ratio) @@ -204,7 +204,7 @@ def get_preview_size(self) -> tuple[int, int]: self.size().height(), ) - def switch_preview(self, preview: str): + def switch_preview(self, preview: str) -> None: if preview in ["audio", "video"]: self.media_player.show() self.image_layout.setCurrentWidget(self.media_player_page) @@ -229,7 +229,7 @@ def switch_preview(self, preview: str): self.gif_buffer.close() self.preview_gif.hide() - def _display_fallback_image(self, filepath: Path, ext: str) -> dict: + def _display_fallback_image(self, filepath: Path, ext: str) -> dict[str, int]: """Renders the given file as an image, no matter its media type. Useful for fallback scenarios. @@ -244,9 +244,9 @@ def _display_fallback_image(self, filepath: Path, ext: str) -> dict: ) return self._update_image(filepath, ext) - def _update_image(self, filepath: Path, ext: str) -> dict: + def _update_image(self, filepath: Path, ext: str) -> dict[str, int]: """Update the static image preview from a filepath.""" - stats: dict = {} + stats: dict[str, int] = {} self.switch_preview("image") image: Image.Image | None = None @@ -287,9 +287,9 @@ def _update_image(self, filepath: Path, ext: str) -> dict: return stats - def _update_animation(self, filepath: Path, ext: str) -> dict: + def _update_animation(self, filepath: Path, ext: str) -> dict[str, int]: """Update the animated image preview from a filepath.""" - stats: dict = {} + stats: dict[str, int] = {} # Ensure that any movie and buffer from previous animations are cleared. if self.preview_gif.movie(): @@ -351,8 +351,8 @@ def _get_video_res(self, filepath: str) -> tuple[bool, QSize]: image = Image.fromarray(frame) return (success, QSize(image.width, image.height)) - def _update_media(self, filepath: Path, type: MediaType) -> dict: - stats: dict = {} + def _update_media(self, filepath: Path, type: MediaType) -> dict[str, int]: + stats: dict[str, int] = {} self.media_player.play(filepath) @@ -380,9 +380,9 @@ def _update_media(self, filepath: Path, type: MediaType) -> dict: stats["duration"] = self.media_player.player.duration() * 1000 return stats - def update_preview(self, filepath: Path, ext: str) -> dict: + def update_preview(self, filepath: Path, ext: str) -> dict[str, int]: """Render a single file preview.""" - stats: dict = {} + stats: dict[str, int] = {} # Video if MediaCategories.is_ext_in_category( @@ -448,17 +448,11 @@ def update_preview(self, filepath: Path, ext: str) -> dict: return stats - def hide_preview(self): + def hide_preview(self) -> None: """Completely hide the file preview.""" self.switch_preview("") - def stop_file_use(self): - """Stops the use of the currently previewed file. Used to release file permissions.""" - logger.info("[PreviewThumb] Stopping file use in video playback...") - # This swaps the video out for a placeholder so the previous video's file - # is no longer in use by this object. - self.media_player.play(ResourceManager.get_path("placeholder_mp4")) - - def resizeEvent(self, event: QResizeEvent) -> None: # noqa: N802 + @override + def resizeEvent(self, event: QResizeEvent) -> None: self.update_image_size((self.size().width(), self.size().height())) return super().resizeEvent(event) diff --git a/src/tagstudio/resources/qt/videos/placeholder.mp4 b/src/tagstudio/resources/qt/videos/placeholder.mp4 deleted file mode 100644 index 1e22e4c72..000000000 Binary files a/src/tagstudio/resources/qt/videos/placeholder.mp4 and /dev/null differ