From efb062034dc9d11eee91ace17107fab54194af51 Mon Sep 17 00:00:00 2001 From: VasigaranAndAngel <72515046+VasigaranAndAngel@users.noreply.github.com> Date: Mon, 5 May 2025 03:43:34 +0530 Subject: [PATCH] refactor: remove placeholder video, fix type hints in preview_thumb.py (#906) * type fixes * remove `stop_file_use()` method and release the file properly. * remove "placeholder_mp4" from resources.json --- src/tagstudio/qt/resources.json | 4 -- src/tagstudio/qt/ts_qt.py | 2 +- src/tagstudio/qt/widgets/media_player.py | 4 +- .../qt/widgets/preview/preview_thumb.py | 46 ++++++++---------- .../resources/qt/videos/placeholder.mp4 | Bin 2590 -> 0 bytes 5 files changed, 23 insertions(+), 33 deletions(-) delete mode 100644 src/tagstudio/resources/qt/videos/placeholder.mp4 diff --git a/src/tagstudio/qt/resources.json b/src/tagstudio/qt/resources.json index 216b9a2b..c2404889 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 804f5098..a45c2eac 100644 --- a/src/tagstudio/qt/ts_qt.py +++ b/src/tagstudio/qt/ts_qt.py @@ -1045,7 +1045,7 @@ class QtDriver(DriverMixin, QObject): 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 807b6699..9d4eaf7b 100644 --- a/src/tagstudio/qt/widgets/media_player.py +++ b/src/tagstudio/qt/widgets/media_player.py @@ -416,9 +416,9 @@ class MediaPlayer(QGraphicsView): 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 7440da82..4b397226 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.file_tester import is_readable_video 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 @@ Image.MAX_IMAGE_PIXELS = None 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 @@ class PreviewThumb(QWidget): 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 @@ class PreviewThumb(QWidget): 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 @@ class PreviewThumb(QWidget): 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 @@ class PreviewThumb(QWidget): 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 @@ class PreviewThumb(QWidget): ) 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 @@ class PreviewThumb(QWidget): 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 @@ class PreviewThumb(QWidget): 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 @@ class PreviewThumb(QWidget): 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 @@ class PreviewThumb(QWidget): 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 1e22e4c724aeefa2a44b44f3462f075495373b1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2590 zcmdT`&1)M+6d$c+MRpZejve9mp}-u$ss+Ac30A({p#*$ z69)o0rq>>d>7mECy@gW9C6~}b4~5WMA(wpgKWHiKAw_v_b~KVVA1#Fj^0YJW^Y`BD z%)UW{5ZdBfp%VulAsRsrLuZLu^TI}r5K?SKwoS;`_nyT#=t$Z`8Ri4+^Q(Km*evE7 z6#N9HLhifi;tsg-o%<^{fY%G-r?kJ=g{R?KbVuL#edoQ?jq{Ef1#!^gbfcm#HRw6t z3@kgMo3+YfrA`p`YhnE1Pv6dbz8$YW`1;n5XSNsJKjO$V>a=6%i%ay1m|J0N=#5IX zTBTvjSYD=X;u;OwG<4ehG=$)G5E{!mb*uuCc}I#=Bht~(sC%s?ZxCakTo2bHEWM67~K6_N2 z6P62T$$ga{dvY~j*ku`47KzI5&7ukuDn{lhyrnD>RhY@5if^kJi7HMji$oOJ&- zRg6SU9#9sEntUgVDjiZW5>+~^ED}{ZmPJh+Q85xVbyQg-YU=$gs(f6U|T!}b>4R4!4(BA%&QH8W;ygU7)snT@!i3p z-SsSoflNK?#ryH`58x%_WXEzNA;FY57F>rz+5|n=V7}$r7^Ag4$Hzjmi6@fEH44Cj zmHOtbbTMc|f2kL_G?lgEF>ksc--&rF4k@*h9lVo4MjFj24Pe>;5eL$95vh4(p6mBP zt3cNE9Ngpm$1lClbLu*uF#|X9P4_C~&k<~9QVv-h0>^?l=3*|+0>o4oTMgR*uY+fV zG>F|chq2SC9gao#MQ)+I9z8GXA|vy#R#QmBwc=fd>*nCQCVj}jt{nuv?|&SycV>Xa zfN%{BV7D`UrH%BJ+_(SMSE5Qfy`rz=N=WYAf9fHbuR7X8vIkYEj~vflhd%+sHX=XE zHY)jP8)59fXdkjI+ozFfpM{Z{xQCL`I|2_EDEsX~oY=z`eGixe2Y%Os?*Ts|Y1?&P zm?Y_0oB{VeTW}D`k