Skip to content

Commit 9eed3b6

Browse files
feat: implement search equivalence of "jpg" and "jpeg" filetypes (#649)
* feat: implement search equivalence of "jpg" and "jpeg" filetypes in an extensible manner * docs: update completion for search features on roadmap * fix: move FILETYPE_EQUIVALENTS to media_types.py
1 parent 4c3ff42 commit 9eed3b6

File tree

3 files changed

+21
-10
lines changed

3 files changed

+21
-10
lines changed

docs/updates/roadmap.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ Features are broken up into the following priority levels, with nested prioritie
8686
- [ ] GPS Location [LOW]
8787
- [ ] Custom field names [HIGH] [#18](https://github.com/TagStudioDev/TagStudio/issues/18)
8888
- [ ] Search engine [HIGH] [#325](https://github.com/TagStudioDev/TagStudio/issues/325)
89-
- [ ] Boolean operators [HIGH] [#225](https://github.com/TagStudioDev/TagStudio/issues/225), [#314](https://github.com/TagStudioDev/TagStudio/issues/314)
89+
- [x] Boolean operators [HIGH] [#225](https://github.com/TagStudioDev/TagStudio/issues/225), [#314](https://github.com/TagStudioDev/TagStudio/issues/314)
9090
- [ ] Tag objects + autocomplete [HIGH] [#476 (Autocomplete)](https://github.com/TagStudioDev/TagStudio/issues/476)
91-
- [ ] Filename search [HIGH]
92-
- [ ] Filetype search [HIGH]
93-
- [ ] Search by extension (e.g. ".jpg", ".png") [HIGH]
94-
- [ ] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW]
95-
- [ ] Search by media type (e.g. "image", "video", "document") [MEDIUM]
91+
- [x] Filename search [HIGH]
92+
- [x] Filetype search [HIGH]
93+
- [x] Search by extension (e.g. ".jpg", ".png") [HIGH]
94+
- [x] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW]
95+
- [x] Search by media type (e.g. "image", "video", "document") [MEDIUM]
9696
- [ ] Field content search [HIGH] [#272](https://github.com/TagStudioDev/TagStudio/issues/272)
9797
- [ ] HAS operator for composition tags [HIGH]
9898
- [ ] OCR search [LOW]
@@ -172,12 +172,12 @@ These version milestones are rough estimations for when the previous core featur
172172
- [ ] [Tag Categories](../library/tag_categories.md) [HIGH]
173173
- [ ] 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]
174174
- [ ] Search engine [HIGH]
175-
- [ ] Boolean operators [HIGH]
175+
- [x] Boolean operators [HIGH]
176176
- [ ] Tag objects + autocomplete [HIGH]
177177
- [x] Filename search [HIGH]
178178
- [x] Filetype search [HIGH]
179179
- [x] Search by extension (e.g. ".jpg", ".png") [HIGH]
180-
- [ ] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW]
180+
- [x] Optional consolidation of extension synonyms (i.e. ".jpg" can equal ".jpeg") [LOW]
181181
- [x] Search by media type (e.g. "image", "video", "document") [MEDIUM]
182182
- [ ] Field content search [HIGH]
183183
- [ ] Sortable results [HIGH]

tagstudio/src/core/library/alchemy/visitors.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from sqlalchemy import and_, distinct, func, or_, select
44
from sqlalchemy.orm import Session
55
from sqlalchemy.sql.expression import BinaryExpression, ColumnExpressionArgument
6-
from src.core.media_types import MediaCategories
6+
from src.core.media_types import FILETYPE_EQUIVALENTS, MediaCategories
77
from src.core.query_lang import BaseVisitor
88
from src.core.query_lang.ast import AST, ANDList, Constraint, ConstraintType, Not, ORList, Property
99

@@ -17,6 +17,13 @@
1717
Library = None # don't import .library because of circular imports
1818

1919

20+
def get_filetype_equivalency_list(item: str) -> list[str] | set[str]:
21+
for s in FILETYPE_EQUIVALENTS:
22+
if item in s:
23+
return s
24+
return [item]
25+
26+
2027
class SQLBoolExpressionBuilder(BaseVisitor[ColumnExpressionArgument]):
2128
def __init__(self, lib: Library) -> None:
2229
super().__init__()
@@ -73,7 +80,9 @@ def visit_constraint(self, node: Constraint) -> ColumnExpressionArgument:
7380
break
7481
return Entry.suffix.in_(map(lambda x: x.replace(".", ""), extensions))
7582
elif node.type == ConstraintType.FileType:
76-
return Entry.suffix.ilike(node.value)
83+
return or_(
84+
*[Entry.suffix.ilike(ft) for ft in get_filetype_equivalency_list(node.value)]
85+
)
7786
elif node.type == ConstraintType.Special: # noqa: SIM102 unnecessary once there is a second special constraint
7887
if node.value.lower() == "untagged":
7988
return ~Entry.id.in_(

tagstudio/src/core/media_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
logging.basicConfig(format="%(message)s", level=logging.INFO)
1212

13+
FILETYPE_EQUIVALENTS = [set(["jpg", "jpeg"])]
14+
1315

1416
class MediaType(str, Enum):
1517
"""Names of media types."""

0 commit comments

Comments
 (0)