Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/tagstudio/qt/resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,5 @@
"thumb_loading": {
"path": "qt/images/thumb_loading.png",
"mode": "pil"
},
"placeholder_mp4": {
"path": "qt/videos/placeholder.mp4",
"mode": "rb"
}
}
2 changes: 1 addition & 1 deletion src/tagstudio/qt/ts_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions src/tagstudio/qt/widgets/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
46 changes: 20 additions & 26 deletions src/tagstudio/qt/widgets/preview/preview_thumb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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__)
Expand All @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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():
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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)
Binary file removed src/tagstudio/resources/qt/videos/placeholder.mp4
Binary file not shown.