-
-
Notifications
You must be signed in to change notification settings - Fork 394
Refactor video_player.py
(Fix #270)
#274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Move icons files to qt/images folder, some being renamed - Reduce icon loading to single initial import - Tweak icon dimensions and animation timings - Remove unnecessary commented code - Remove unused/duplicate imports - Add license info to file
Hmmmm, not seeing icons in the exe build but that might be something on my end. |
I think its because its a local path so tagstudio is no longer valid after packaging, swapping to I think we need to figure out how to incorporate that into the resources_rc file and then change the path to be similar to the way the splash screen is loaded. |
I wonder why these are the only assets breaking when all of the other assets that aren't in the resources_rc are still working... And I tested out building it on my end beforehand, at least the portable version, and it worked with this change |
Hmmm does it work for you as is with
|
@CyanVoxel I somehow pulled an old version of this PR sorry for the confusion |
Great news haha 😁 |
with open(Path(_parents, "resources/qt/images/pause.svg"), "rb") as icon: | ||
pause_icon = bytes(icon.read()) | ||
|
||
with open(Path(_parents, "resources/qt/images/play.svg"), "rb") as icon: | ||
play_icon = bytes(icon.read()) | ||
|
||
with open(Path(_parents, "resources/qt/images/volume.svg"), "rb") as icon: | ||
volume_icon = bytes(icon.read()) | ||
|
||
with open(Path(_parents, "resources/qt/images/volume_mute.svg"), "rb") as icon: | ||
volume_mute_icon = bytes(icon.read()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd keep these resources outside of the VideoPlayer
class, and rather have another class for handling this kind of assets, ResourceManager
or something like that. Then it can be used across the whole codebase for all the resources, which would be nicer than doing open(Path(_parents, "resources/qt/something/something
))` everywhere.
This will provide some level of abstraction, so if/when the underlying implementation will change, it wont affect any code using the resources.
Something like this:
class ResourceManager:
MAP = {
"play_icon": "qt/images/play.svg",
# ...
}
def _load(self, id: str):
# eventually implement cache like
# if id in self.CACHE: return self.CACHE[id]
with open(self.MAP[id], 'rb') as f:
return f.read()
def get(self, id: str):
"""Allow to use the manager as:
r = ResourceManager()
r.get('play_icon')
"""
return self._load(id)
def __getattr__(self, id: str):
"""Allow to use the manager as:
r = ResourceManager()
r.play_icon
"""
if id in self.MAP:
return self._load(id)
raise AttributeError(f'attribute {id} not found')
For the Qt side I'd be leaning toward utilizing the built-in resource manager This would let the resources be managed outside this file and hopefully avoid future path issues for them. though it does add a step to remember whenever we want to add an image asset, and these are technically hidden imports as they aren't exposed to python so much as a resource made available to Qt in the background by that Adding these images to the resources.qrc file <!-- TO COMPILE: pyside6-rcc resources.qrc -o resources_rc.py (in \tagstudio\src\qt)-->
<RCC>
<qresource prefix="/">
<file alias = "images/star_icon_empty_128.png">../../resources/qt/images/star_icon_empty_128.png</file>
<file alias = "images/star_icon_filled_128.png">../../resources/qt/images/star_icon_filled_128.png</file>
<file alias = "images/box_icon_empty_128.png">../../resources/qt/images/box_icon_empty_128.png</file>
<file alias = "images/box_icon_filled_128.png">../../resources/qt/images/box_icon_filled_128.png</file>
<!-- <file alias = "images/edit_icon_128.png">../../resources/qt/images/edit_icon_128.png</file> -->
<!-- <file alias = "images/trash_icon_128.png">../../resources/qt/images/trash_icon_128.png</file> -->
<!-- <file alias = "images/clipboard_icon_128.png">../../resources/qt/images/clipboard_icon_128.png</file> -->
<file alias = "images/splash.png">../../resources/qt/images/splash.png</file>
<file alias = "images/pause.svg">../../resources/qt/images/pause.svg</file>
<file alias = "images/play.svg">../../resources/qt/images/play.svg</file>
<file alias = "images/volume_mute.svg">../../resources/qt/images/volume_mute.svg</file>
<file alias = "images/volume.svg">../../resources/qt/images/volume.svg</file>
</qresource>
</RCC> would let you only reference these images with a colon and their alias so the update controls function on L182 ends up like this. def updateControls(self) -> None:
if self.player.audioOutput().isMuted():
self.mute_button.load(":images/volume_mute.svg")
else:
self.mute_button.load(":images/volume.svg")
if self.player.isPlaying():
self.play_pause.load(":images/pause.svg")
else:
self.play_pause.load(":images/play.svg") |
I've added a basic I've tested the resource changes in the executable build as well and have found no regressions with the resource fix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would sure work, but maybe there's some room for improvement
tagstudio/src/qt/resource_manager.py
Outdated
if cached_res: | ||
return cached_res | ||
else: | ||
path, mode = ResourceManager._map.get(id, None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will raise exception in case the resource is not present in ._map
, because at that point the value you will get is None
, and that cant be assigned into two variables path, mode
:
>>> path, mode = None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot unpack non-iterable NoneType object
storing the data as dictionary inside _map
instead of extracted properties would prevent this issue.
btw. the default fallback value of .get()
is None
, so no need to define that explicitly as the second parameter of .get()
assert dict().get('foo') is None
|
||
resolution = QSize(1280, 720) | ||
hover_fix_timer = QTimer() | ||
rm: ResourceManager = ResourceManager() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd initialize this class inside QtDriver
instead of here, as this will be needed in other places in the codebase as well, and that way you'll have the same instance available everywhere. Since driver
is passed here, then it would be used as self.driver.rm.play_icon
instead of VideoPlayer.rm.play_icon
tagstudio/src/qt/resource_manager.py
Outdated
# Initialize _map | ||
with open( | ||
Path(__file__).parent / "resources.json", mode="r", encoding="utf-8" | ||
) as f: | ||
json_map: dict = ujson.load(f) | ||
for item in json_map.items(): | ||
_map[item[0]] = (item[1]["path"], item[1]["mode"]) | ||
|
||
logging.info(f"[ResourceManager] Resources Loaded: {_map}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
this would be better to do in constructor, otherwise doing
import
of this class will have "side-effect" (ie. opening and loading from json file), similar way as doingimport src.qt.resources_rc
has side-effect of prefilling some QT resources -
when using
.items()
, you can work with it as two variables (key, value), so you dont have to unpack it via numeric index (item[0]
item[1]
) later
-for item in json_map.items():
- _map[item[0]] = (item[1]["path"], item[1]["mode"])
+ for key, value in json_map.items():
+ _map[key] = (value["path"], value["mode"])
- to make this future-proof, I'd assign just the whole
value
instead of extracting specific keys in case there will be some other property in future. This will also mitigate a potential issue further on (see my other comment elsewhere)
-_map[key] = (value["path"], value["mode"])
+_map[key] = value
...and at that point you can do just this:
-json_map: dict = ujson.load(f)
-for item in json_map.items():
- _map[item[0]] = (item[1]["path"], item[1]["mode"])
+_map = ujson.load(f)
tagstudio/src/qt/resource_manager.py
Outdated
res.get("mode"), | ||
) as f: | ||
data = f.read() | ||
if res.get("mode") == ["rb"]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if res.get("mode") == ["rb"]: | |
if res.get("mode") == "rb": |
Thanks for the review, @yedpodtrzitko ! |
Ports the following thumbnail and related PRs from the `Alpha-v9.4` branch to `main` (v9.5+): - (#273) Blender thumbnail support - (#307) Add font thumbnail preview support - (#331) refactor: move type constants to new media classes - (#390) feat(ui): expanded thumbnail and preview features - (#370) ui: "open in explorer" action follows os name - (#373) feat(ui): preview support for source engine files - (#274) Refactor video_player.py (Fix #270) - (#430) feat(ui): show file creation/modified dates + restyle path label - (#471) fix(ui): use default audio icon if ffmpeg is absent - (#472) fix(ui): use birthtime for creation time on mac & win Co-Authored-By: Ethnogeny <111099761+050011-code@users.noreply.github.com> Co-Authored-By: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Co-Authored-By: SupKittyMeow <77246128+supkittymeow@users.noreply.github.com> Co-Authored-By: EJ Stinson <93455158+favroitegamers@users.noreply.github.com> Co-Authored-By: Sean Krueger <71362472+seakrueger@users.noreply.github.com>
* feat: port v9.4 thumbnail + related feats to v9.5 Ports the following thumbnail and related PRs from the `Alpha-v9.4` branch to `main` (v9.5+): - (#273) Blender thumbnail support - (#307) Add font thumbnail preview support - (#331) refactor: move type constants to new media classes - (#390) feat(ui): expanded thumbnail and preview features - (#370) ui: "open in explorer" action follows os name - (#373) feat(ui): preview support for source engine files - (#274) Refactor video_player.py (Fix #270) - (#430) feat(ui): show file creation/modified dates + restyle path label - (#471) fix(ui): use default audio icon if ffmpeg is absent - (#472) fix(ui): use birthtime for creation time on mac & win Co-Authored-By: Ethnogeny <111099761+050011-code@users.noreply.github.com> Co-Authored-By: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Co-Authored-By: SupKittyMeow <77246128+supkittymeow@users.noreply.github.com> Co-Authored-By: EJ Stinson <93455158+favroitegamers@users.noreply.github.com> Co-Authored-By: Sean Krueger <71362472+seakrueger@users.noreply.github.com> * remove vscode exceptions from `.gitignore` * delete .vscode directory * style: format for `ruff check` * fix(tests): update `test_update_widgets_not_selected` test * remove Send2Trash dependency * refactor: use dataclass for MediaCateogry * refactor: use enums for UI colors * docs: add file docstring for silent_Popen * refactor: replace logger with structlog * use early return inside `ResourceManager.get()` * add `is_ext_in_category()` method to `MediaCategory` Add method to check if an extension is a member of a given MediaCategory. * style: fix docstring style, missing type hints, rename `afm` * fix: use structlog vars in logging * refactor: move platform-dependent strings to PlatformStrings * refactor: move `parents[2]` path to variable * fix: undo logger regressions --------- Co-authored-by: Ethnogeny <111099761+050011-code@users.noreply.github.com> Co-authored-by: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Co-authored-by: SupKittyMeow <77246128+supkittymeow@users.noreply.github.com> Co-authored-by: EJ Stinson <93455158+favroitegamers@users.noreply.github.com> Co-authored-by: Sean Krueger <71362472+seakrueger@users.noreply.github.com>
This PR makes various changes to
video_player.py
, with many involving where the SVG icons are stored and how they're loaded. In the process this fixes #270.Changes