From a4ce773faaf8498d55637e0d202258549337025f Mon Sep 17 00:00:00 2001 From: Jann Stute Date: Tue, 17 Dec 2024 19:44:45 +0100 Subject: [PATCH 1/3] feat: implement search equivalence of "jpg" and "jpeg" filetypes in an extensible manner --- tagstudio/src/core/library/alchemy/visitors.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tagstudio/src/core/library/alchemy/visitors.py b/tagstudio/src/core/library/alchemy/visitors.py index 6f73a45a2..e9a9159c9 100644 --- a/tagstudio/src/core/library/alchemy/visitors.py +++ b/tagstudio/src/core/library/alchemy/visitors.py @@ -16,6 +16,15 @@ else: Library = None # don't import .library because of circular imports +FILETYPE_EQUIVALENTS = [set(["jpg", "jpeg"])] + + +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[ColumnExpressionArgument]): def __init__(self, lib: Library) -> None: @@ -73,7 +82,9 @@ def visit_constraint(self, node: Constraint) -> ColumnExpressionArgument: break return Entry.suffix.in_(map(lambda x: x.replace(".", ""), extensions)) elif node.type == ConstraintType.FileType: - return Entry.suffix.ilike(node.value) + return or_( + *[Entry.suffix.ilike(ft) for ft in get_filetype_equivalency_list(node.value)] + ) elif node.type == ConstraintType.Special: # noqa: SIM102 unnecessary once there is a second special constraint if node.value.lower() == "untagged": return ~Entry.id.in_( From 2ef96ff19eeb1b15dbb593c290849a410e4cb8c8 Mon Sep 17 00:00:00 2001 From: Jann Stute Date: Tue, 17 Dec 2024 19:56:19 +0100 Subject: [PATCH 2/3] docs: update completion for search features on roadmap --- docs/updates/roadmap.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/updates/roadmap.md b/docs/updates/roadmap.md index e204bc3b4..7a8e25578 100644 --- a/docs/updates/roadmap.md +++ b/docs/updates/roadmap.md @@ -86,13 +86,13 @@ Features are broken up into the following priority levels, with nested prioritie - [ ] GPS Location [LOW] - [ ] Custom field names [HIGH] [#18](https://github.com/TagStudioDev/TagStudio/issues/18) - [ ] Search engine [HIGH] [#325](https://github.com/TagStudioDev/TagStudio/issues/325) - - [ ] Boolean operators [HIGH] [#225](https://github.com/TagStudioDev/TagStudio/issues/225), [#314](https://github.com/TagStudioDev/TagStudio/issues/314) + - [x] Boolean operators [HIGH] [#225](https://github.com/TagStudioDev/TagStudio/issues/225), [#314](https://github.com/TagStudioDev/TagStudio/issues/314) - [ ] Tag objects + autocomplete [HIGH] [#476 (Autocomplete)](https://github.com/TagStudioDev/TagStudio/issues/476) - - [ ] Filename search [HIGH] - - [ ] Filetype search [HIGH] - - [ ] Search by extension (e.g. ".jpg", ".png") [HIGH] - - [ ] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW] - - [ ] Search by media type (e.g. "image", "video", "document") [MEDIUM] + - [x] Filename search [HIGH] + - [x] Filetype search [HIGH] + - [x] Search by extension (e.g. ".jpg", ".png") [HIGH] + - [x] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW] + - [x] Search by media type (e.g. "image", "video", "document") [MEDIUM] - [ ] Field content search [HIGH] [#272](https://github.com/TagStudioDev/TagStudio/issues/272) - [ ] HAS operator for composition tags [HIGH] - [ ] OCR search [LOW] @@ -172,12 +172,12 @@ These version milestones are rough estimations for when the previous core featur - [ ] [Tag Categories](../library/tag_categories.md) [HIGH] - [ ] Property available for tags that allow the tag and any inheriting from it to be displayed separately in the preview panel under a title [HIGH] - [ ] Search engine [HIGH] - - [ ] Boolean operators [HIGH] + - [x] Boolean operators [HIGH] - [ ] Tag objects + autocomplete [HIGH] - [x] Filename search [HIGH] - [x] Filetype search [HIGH] - [x] Search by extension (e.g. ".jpg", ".png") [HIGH] - - [ ] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW] + - [x] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW] - [x] Search by media type (e.g. "image", "video", "document") [MEDIUM] - [ ] Field content search [HIGH] - [ ] Sortable results [HIGH] From d794c055aa92dbc74873bf668f5404a907097673 Mon Sep 17 00:00:00 2001 From: Jann Stute Date: Sat, 21 Dec 2024 03:12:30 +0100 Subject: [PATCH 3/3] fix: move FILETYPE_EQUIVALENTS to media_types.py --- tagstudio/src/core/library/alchemy/visitors.py | 4 +--- tagstudio/src/core/media_types.py | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tagstudio/src/core/library/alchemy/visitors.py b/tagstudio/src/core/library/alchemy/visitors.py index e9a9159c9..1756bb089 100644 --- a/tagstudio/src/core/library/alchemy/visitors.py +++ b/tagstudio/src/core/library/alchemy/visitors.py @@ -3,7 +3,7 @@ from sqlalchemy import and_, distinct, func, or_, select from sqlalchemy.orm import Session from sqlalchemy.sql.expression import BinaryExpression, ColumnExpressionArgument -from src.core.media_types import MediaCategories +from src.core.media_types import FILETYPE_EQUIVALENTS, MediaCategories from src.core.query_lang import BaseVisitor from src.core.query_lang.ast import AST, ANDList, Constraint, ConstraintType, Not, ORList, Property @@ -16,8 +16,6 @@ else: Library = None # don't import .library because of circular imports -FILETYPE_EQUIVALENTS = [set(["jpg", "jpeg"])] - def get_filetype_equivalency_list(item: str) -> list[str] | set[str]: for s in FILETYPE_EQUIVALENTS: diff --git a/tagstudio/src/core/media_types.py b/tagstudio/src/core/media_types.py index 78755aace..be9ebdbdf 100644 --- a/tagstudio/src/core/media_types.py +++ b/tagstudio/src/core/media_types.py @@ -10,6 +10,8 @@ logging.basicConfig(format="%(message)s", level=logging.INFO) +FILETYPE_EQUIVALENTS = [set(["jpg", "jpeg"])] + class MediaType(str, Enum): """Names of media types."""