Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5ada5c9
feat!: establish new MediaType system
CyanVoxel Aug 19, 2026
f66b8a8
further additions and changes
CyanVoxel Aug 20, 2026
22d1b70
begin making renderers classes, improve text thumbnails
CyanVoxel Aug 21, 2026
57bf2a5
continue renderer work
CyanVoxel Aug 22, 2026
c6a2600
convert most remaining thumbnail renderers to classes
CyanVoxel Aug 22, 2026
d3a0432
feat: dynamically load preview renderers
CyanVoxel Aug 22, 2026
bf0a982
refactor: use individual ext registration, continued progress
CyanVoxel Aug 29, 2026
a5c0072
refactor: finish converting old types to new registration system
CyanVoxel Aug 30, 2026
6f0d144
chore: alphabetize lists
CyanVoxel Aug 30, 2026
db9d3c4
fix: only use search context for searches
CyanVoxel Aug 31, 2026
ab31663
refactor: remove legacy filetype equivalent usages
CyanVoxel Aug 31, 2026
36b30cd
feat: add aliases for type groups, used in search
CyanVoxel Aug 31, 2026
0b0f69e
refactor: use new MediaTypes system in archive renderers
CyanVoxel Sep 1, 2026
cf09d84
fix: add missing types
CyanVoxel Sep 1, 2026
08c7aef
refactor: remove last uses of legacy media type system
CyanVoxel Sep 1, 2026
37090de
refactor: move media type search context init to new file
CyanVoxel Sep 1, 2026
4f31f2c
fix: fix import formatting, add missing aliases
CyanVoxel Sep 1, 2026
698f539
chore: remove leftover logging
CyanVoxel Sep 1, 2026
0d339d7
chore: small tweaks and comments
CyanVoxel Sep 1, 2026
95b7c74
refactor: wrap filetype init in function, call in driver
CyanVoxel Sep 1, 2026
75051d6
docs: add and update docstrings
CyanVoxel Sep 1, 2026
f48addc
fix: use all intended fallback icons for each media type
CyanVoxel Sep 2, 2026
b27581b
fix: fix misc issues
CyanVoxel Sep 2, 2026
8ac57f9
tests: add test cases for media types
CyanVoxel Sep 2, 2026
7c4a9a6
refactor: rename register_all to register_types
CyanVoxel Sep 7, 2026
a85723a
refactor: wrap preview renderer type registrations in methods
CyanVoxel Sep 7, 2026
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
11 changes: 11 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,14 @@ path = [
]
SPDX-FileCopyrightText = "(c) github:google/material-design-icons Contributors"
SPDX-License-Identifier = "Apache-2.0"

[[annotations]]
path = ["src/tagstudio/resources/qt/fonts/Oxanium-Bold.ttf"]
SPDX-FileCopyrightText = "(c) 2019 The Oxanium Project Authors (https://github.com/sevmeyer/oxanium)"
SPDX-License-Identifier = "OFL-1.1"


[[annotations]]
path = ["src/tagstudio/resources/fonts/JetBrainsMono/**"]
SPDX-FileCopyrightText = "(c) 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)"
SPDX-License-Identifier = "OFL-1.1"
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ dependencies = [
"mutagen~=1.47",
"numpy~=2.2",
"opencv_python~=4.11",
"Pillow>=10.2,<12",
"pillow-heif~=1.5.0",
"pillow-jxl-plugin~=1.3",
"Pillow>=10.2,<12",
"py7zr~=1.1.3",
"pydantic~=2.10",
"pydub~=0.25",
"Pygments~=2.21",
"PySide6==6.11.2",
"rarfile==4.2",
"rawpy~=0.27",
"requests~=2.31.0",
"semver~=3.0.4",
"Send2Trash>=1.8,<3",
"SQLAlchemy~=2.0",
"srctools~=2.6",
Expand All @@ -38,8 +41,6 @@ dependencies = [
"typing_extensions~=4.13",
"ujson~=5.10",
"wcmatch==10.*",
"requests~=2.31.0",
"semver~=3.0.4",
]

[project.gui-scripts]
Expand Down
3 changes: 3 additions & 0 deletions src/tagstudio/core/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from tagstudio.core.constants import TS_FOLDER_NAME
from tagstudio.core.enums import AppCacheItems
from tagstudio.core.library.alchemy.library import LibraryStatus
from tagstudio.core.query_lang.file_groups import register_types
from tagstudio.qt.app_settings import AppSettings

logger = structlog.get_logger(__name__)
Expand All @@ -21,6 +22,8 @@ class DriverMixin:
# TODO: AppSettings is Qt-specific and should not be in a base driver class.
settings: AppSettings

register_types() # Register all filetypes for the SEARCH context.

def evaluate_path(self, open_path: str | None) -> LibraryStatus:
"""Check if the path of library is valid."""
library_path: Path | None = None
Expand Down
9 changes: 8 additions & 1 deletion src/tagstudio/core/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class TagClickActionOption(enum.IntEnum):
DEFAULT = OPEN_EDIT


class Theme(enum.StrEnum):
class ThemePalette(enum.StrEnum):
COLOR_BG_DARK = "#65000000"
COLOR_BG_LIGHT = "#22000000"
COLOR_DARK_LABEL = "#DD000000"
Expand All @@ -44,6 +44,13 @@ class Theme(enum.StrEnum):
COLOR_FORBIDDEN_BG = "#65440D12"


class Theme(enum.IntEnum):
DARK = 0
LIGHT = 1
SYSTEM = 2
DEFAULT = SYSTEM


class OpenStatus(enum.IntEnum):
NOT_FOUND = 0
SUCCESS = 1
Expand Down
34 changes: 20 additions & 14 deletions src/tagstudio/core/library/alchemy/visitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from tagstudio.core.library.alchemy.constants import TAG_CHILDREN_ID_QUERY
from tagstudio.core.library.alchemy.joins import TagEntry
from tagstudio.core.library.alchemy.models import Entry, Tag, TagAlias
from tagstudio.core.media_types import FILETYPE_EQUIVALENTS, MediaCategories
from tagstudio.core.media_types import MediaTypeGroup, MediaTypes
from tagstudio.core.query_lang.ast import (
AST,
ANDList,
Expand All @@ -24,6 +24,7 @@
ORList,
Property,
)
from tagstudio.core.query_lang.file_groups import SEARCH

# Only import for type checking/autocompletion, will not be imported at runtime.
if TYPE_CHECKING:
Expand All @@ -34,13 +35,6 @@
logger = structlog.get_logger(__name__)


def get_filetype_equivalency_list(item: str) -> list[str] | set[str]:
for s in FILETYPE_EQUIVALENTS:
if item in s:
return s
return [item]


class SQLBoolExpressionBuilder(BaseVisitor[ColumnElement[bool]]):
def __init__(self, lib: Library) -> None:
super().__init__()
Expand Down Expand Up @@ -95,15 +89,27 @@ def visit_constraint(self, node: Constraint) -> ColumnElement[bool]:
)
return Entry.path.regexp_match(re.escape(node.value))
elif node.type == ConstraintType.MediaType:
extensions: set[str] = set[str]()
for media_cat in MediaCategories.ALL_CATEGORIES:
if node.value == media_cat.name:
extensions = extensions | media_cat.extensions
break
key = (
MediaTypes.get_group_key_from_name(
node.value, case_sensitive=False, ignore_whitespace=True
)
or node.value
)

media_type: MediaTypeGroup | None = getattr(MediaTypes, key, None)
extensions: set[str] = (
media_type.context_sets.get(SEARCH, set()) if media_type else set()
)
return Entry.suffix.in_(map(lambda x: x.replace(".", ""), extensions))

elif node.type == ConstraintType.FileType:
# NOTE: Entries store their suffix without a leading dot, the MediaTypes system includes
# the leading dot (if any), and this search system should take in either variant.
return or_(
*[Entry.suffix.ilike(ft) for ft in get_filetype_equivalency_list(node.value)]
*[
Entry.suffix.ilike(ft.removeprefix("."))
for ft in MediaTypes.get_equivalent_exts(f".{node.value.removeprefix('.')}")
]
)
elif node.type == ConstraintType.Special: # noqa: SIM102 unnecessary once there is a second special constraint
if node.value.lower() == "untagged":
Expand Down
9 changes: 8 additions & 1 deletion src/tagstudio/core/library/refresh.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,14 @@ def __get_dir_list(self, library_dir: Path, ignore_patterns: list[str]) -> list[
shell=True,
encoding="UTF-8",
)
compiled_ignore_path.unlink()
try:
compiled_ignore_path.unlink()
except Exception as e:
logger.error(
"[Refresh] Could not remove compiled ignore path",
path=compiled_ignore_path,
error=e,
)

if result.stderr:
logger.error(result.stderr)
Expand Down
Loading
Loading